原因
public class LambdaTest {long l = 1L;private void test() {String s = "aaa";Object localObj2 = new Object();Integer a = 0;Consumer consumer = (x) -> {System.out.println(x);System.out.println(l);System.out.println(s);System.out.println(a);};consumer.accept(localObj2);}}
之后编译该类,反编译字节码:
javac src/LambdaTest.javajavap -p src/LambdaTest.class输出:Compiled from "LambdaTest.java"public class LambdaTest {long l;public LambdaTest();private void test();private void lambda$test$0(java.lang.String, java.lang.Integer, java.lang.Object);}
相当于
long l = 1L;private void test() {String s = "aaa";Object localObj2 = new Object();Integer a = 0;testlambda(localObj2,s,a);}private void testlambda(Object x,String s,Integer a){System.out.println(x);System.out.println(this.l);System.out.println(s);System.out.println(a);}
由此可看出,Lambda表达式是一个语法糖,会被编译生成为当前类的一个私有方法,Lambda表达式内直接引用局部变量本质是一种隐式传参,编译时会自动将引用的局部变量放到参数列表中(Lambda方法多了个参数),而引用的实例变量并不需要放到参数列表,因为方法内可以直接引用。
所以在Lambda中对参数重新赋值或者在方法中将局部变量重新赋值,对另一方都是没有影响的。
因此,为了避免这种误导混淆,保证局部变量和Lambda的变量副本的数据一致性,Java直接在语法层面强制Lambda表达式引用的局部变量不可被重新赋值。
