问题重现:
public void test() {
List<Integer> list = new ArrayList<>();
int sum = 0;
list.forEach(a -> {
sum += a;
});
}
public void test() {
List<Integer> list = new ArrayList<>();
list.forEach(a -> {
list = new ArrayList<>();
});
}
上面两段代码都会报错:Variable used in lambda expression should be final or effectively final。
意思是不允许在Lambda表达式中修改使用的(外部)变量。不管是修改对象的引用还是修改基本类型的值都是不可以的。
问题分析:
@Test
public void test1(){
List<String> list = new ArrayList();
Optional.of("aaa").ifPresent(str->{
list.add("ddd");
});
}
这段代码是不会报错的。
Lambda其实是一个匿名函数,在匿名函数里的变量引用,也叫做变量引用泄露,会导致线程安全问题,因此在Java8之前,如果在匿名类内部引用函数局部变量,必须将其声明为final,即不可变对象。
Java8这里加了一个语法糖:在lambda表达式以及匿名类内部,如果引用某局部变量,则直接将其视为final。所以不能修改引用值。
Lambda修改外部基本类型变量值:
使用线程安全Integer的AtomicInteger。
java.util.concurrent.atomic
包下全部是线程安全的包装类。
@Test
public void test1(){
AtomicInteger i = new AtomicInteger(2);
Optional.of("aaa").ifPresent(str->{
i.set(6);
});
System.out.println(i);
}