Lambda表达式
Lambda表达式是Java8的新特性使得代码更为简洁易懂。
如当我们需要依次打印某集合的内容(如水果名字集合),之前我们使用 for 循环来完成打印,但使用Lambda表达式则可以:
fruits.forEach(f -> {
System.out.println(f.getName());
});
其中 f -> {}
,就是 Lambda表达式
其中 f 表示参数变量,其类型取决于上下文的需求,即Lambda表达式需要配合上下文,配合其他语法使用,而不能成为单独的语句。
而 {} 中写入的是方法的主体。
多参数
箭头(->)前表示参数变量,当存在多个参数时,需要用小括号()包裹:
(student1, student2) -> {}
无参数
同理,当没有参数变量时,也需要用小括号()包裹:
() -> {}
注:当箭头后面只有一条执行语句时,可以不用大括号包裹
s -> System.out.println(s);
但在实际使用中最好无论多少条语句都加上 {} 。
当然,所写的参数也可以带类型如:
fruits.forEach((Fruit f) -> {
System.out.println(f.getName());
});
但添加类型后必须用小括号括住,不然会报错。
引用外部变量
Lambda表达式的 { } 内执行的语句,除了能引用参数变量,还可以引用外部变量,但如:
List<Fruit> fruits = Arrays.asList(......);
String message = "水果名称:";
fruits.forEach(f -> {
System.out.println(message + f.getName());
});
message = "";
会报错。
Lambda引用外部变量存在规范:
- 规范一:引用的局部变量 不允许被修改(即使写在表达式后面也不行)
当然写在 { } 内的修改也是不行的。即Lamdba表达式引用的局部变量具备 final 的特性。
在表达式外实际赋值一次的写法是允许的。
- 规范二:参数不能与局部变量同名,如下错误
String f = "水果名称:";
fruits.forEach(f -> {});
双冒号(::)操作符
双冒号可以简化操作:
List<String> names = Arrays.asList("zhangSan", "LiSi", "WangWu");
names.forEach(n -> {
System.out.println(n);
});
简化为:
names.forEach(System.out::println);
使用双冒号时,系统每次遍历取得的元素(n),都和自动传递给需要参数的语句(如System.out.println())
System.out::println
等同于 n -> {System.out.println(n);}
语法含义
用法:
- 用法一:静态方法调用
如使用 LambdaTest::print
代替 f -> LambdaTest.print(f)
,简化了代码
- 用法二:调用非静态方法
print()
方法不再标识为 static
,于是需要实例对象来调用。
fruits.forEach(new LambdaTest()::print);
只是简写了:
LambdaTest lt = new LambdaTest();
fruits.forEach(lt::print);
效果是一样的。
- 用法三:多参数
Collections.sort(students, (student1, student2) -> {
// 第一个参数的学号 vs 第二个参数的学号
return student1.getRollNo() - student2.getRollNo();
});
碰到了多参数的情况。如果把比较的过程定义成一个方法:
private static int compute(Student s1, Student s2) {
... ...
... ...
}
那么,排序过程就可以简写为:
Collections.sort(students, SortTest::compute);
注意,系统会 自动 获取上下文的参数,并按上下文定义的 顺序 传递给指定的方法。所谓 顺序 就是 Lambda 表达式 ()
中的顺序。
- 用法四:父类方法
super
关键字的作用是在子类中引用父类的属性或者方法。那么同样,::
语法也可以用 super
关键词调用父类的非静态方法。