最近在编写一些Java业务,使用了 Lambda语法,所以有必要整理一下lambda相关的知识,以便能够加深理解。
- 什么是lambda表达式?
- lambda语法格式
- lambda 表达式重要特征
- 函数式接口
- lambda使用
- 匿名类和lambda中this指针
- 参考网站
1、什么是lambda表达式?
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda 表达式可以使代码变的更加简洁紧凑。
2、lambda语法格式
(parameters) -> expression
(parameters) -> {expression;}
3、lambda 表达式重要特征
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
4、函数式接口
-
什么是函数式接口:
- 函数式接口(Functional Interface)是Java 8对一类特殊类型的接口的称呼。 这类接口只定义了唯一的抽象方法的接口(除了隐含的Object对象的公共方法), 因此最开始也就做SAM类型的接口(Single Abstract Method)。
- 函数式接口中可以额外定义Object中多个抽象方法,但这些抽象方法签名必须和Object的 public 方法一样
-
Java8新增函数式接口
- Predicate -- 传入一个参数,返回一个bool结果, 方法为boolean test(T t)
- Consumer -- 传入一个参数,无返回值,纯消费。 方法为void accept(T t)
- Function -- 传入一个参数,返回一个结果,方法为R apply(T t)
- Supplier -- 无参数传入,返回一个结果,方法为T get()
- UnaryOperator -- 一元操作符,继承Function,传入参数的类型和返回类型相同。
- BinaryOperator -- 二元操作符, 传入的两个参数的类型和返回类型相同, 继承BiFunction
5、lambda使用
- 循环打印List<Integer>中的值
- 老方法:for(Integer i: list) { System.out.println(i);}
- Lambda表达式:list.forEach(x->System.out.println(x));
public static void main(String... args) {
List<Integer> list = Arrays.asList(10, 5, 4, 1, 76);
for(Integer i: list) {
System.out.println(i);
}
list.forEach(x -> System.out.println(x));
}
-反编译代码
for:
45: aload_1
46: invokeinterface #5, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/I
terator;
51: astore_2
52: aload_2
53: invokeinterface #6, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
58: ifeq 81
61: aload_2
62: invokeinterface #7, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/O
bject;
67: checkcast #2 // class java/lang/Integer
70: astore_3
71: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
74: aload_3
75: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/Object;
)V
78: goto 52
lambda:
81: aload_1
82: invokedynamic #10, 0 // InvokeDynamic #0:accept:()Ljava/util/function/Consumer
;
87: invokeinterface #11, 2 // InterfaceMethod java/util/List.forEach:(Ljava/util/fun
ction/Consumer;)V
private static void lambda$main$0(java.lang.Integer);
Code:
0: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0
4: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/Object;
)V
7: return
- lambda 编译的时候生成了一个动态方法,调用也是执行命令invokedynamic
6、匿名类和lambda中this指针
- 示例代码
public void test1(){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(this.toString());
}
}).start();
new Thread(()->System.out.println(this.toString())).start();
}
- 反编译
public class com.yuxiu.test.Main {
public void test1();
Code:
0: new #5 // class java/lang/Thread
3: dup
4: new #6 // class com/yuxiu/test/Main$1
7: dup
8: aload_0
9: invokespecial #7 // Method com/yuxiu/test/Main$1."<init>":(Lcom/yuxiu/test
/Main;)V
12: invokespecial #8 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;
)V
15: invokevirtual #9 // Method java/lang/Thread.start:()V
18: new #5 // class java/lang/Thread
21: dup
22: aload_0
23: invokedynamic #10, 0 // InvokeDynamic #0:run:(Lcom/yuxiu/test/Main;)Ljava/lang
/Runnable;
28: invokespecial #8 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;
)V
31: invokevirtual #9 // Method java/lang/Thread.start:()V
34: return
private void lambda$test1$0();
Code:
0: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0
4: invokevirtual #12 // Method java/lang/Object.toString:()Ljava/lang/String;
7: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;
)V
10: return
}
- 结论:
匿名类this指向匿名类
lambda中this指向lambda外的类