本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、前提
- 只有在接受函数式接口的地方才可以使用Lambda 表达式
函数式接口: @FunctionalInterface 注解用于表示该接口会设计成一个函数式接口
- 在 Lambda 主体中引用的局部变量必须使用
final修饰。 具体原因: 请跳转
()->{
final String str='';
return str;
}
二、方法引用
- 静态方法的方法引用:
args -> ClassName.staticMethod(args)等价ClassName::staticMethod - 实例方法的方法引用:
args -> expr.instanceMethod(args)等价expr::instanceMethod - 构造函数引用:
new Test()等价ClassName::new
public class Test {
public Test() {
}
public static int staticMethod(int num) {
return num + 1;
}
public int instanceMethod(int num) {
return num - 1;
}
}
public static void main(String[] args){
List<Integer> list = Arrays.asList(1, 2, 3);
//静态方法
list.stream().map(Test::staticMethod).collect(Collectors.toList());
//实例方法
Test test = new Test();
list.stream().map(test::staticMethod).collect(Collectors.toList());
}
三、使用
@FunctionalInterface
public interface text{
int test(int a);
}
public static void main(String[] args){
text t = null;
//第一种使用方式
t = (a) -> 1;
//第二种使用方式
t = a -> a + 1;
//第三种使用方式
t = (int a) -> {
return a - 1;
};
}
四、一些解释
1、为什么 Lambda 主体中引用的局部变量必须使用 final 修饰
- 有效
final变量的限制禁止对动态更改的本地变量(局部变量)的访问,捕获本地变量可能会引入并发问题
例子1:如果你认为流是对每个值求和2,但实际上它是对0求和,因为这是执行lambda时可用的最新值
public int workaroundSingleThread() {
int[] holder = new int[] { 2 };
IntStream sums = IntStream
.of(1, 2, 3)
.map(val -> val + holder[0]);
holder[0] = 0;
return sums.sum();
}
例子2:编译不通过,start是一个局部变量,而且必须是final修饰,因为start值是不能变的,不然在lambda内部递增 start 实际上可以修改 start 方法参数
Supplier<Integer> incrementer(int start) {
return () -> start++;
}