请考虑以下代码:
Integer[] arr = new Integer[] {1,2};
Consumer<Integer> lm1 = a -> {
arr[1] = a; // accepted without any problem
System.out.println(arr[1]);
};
lm1.accept(100);
但是编译器有这个问题:
Integer b = 10;
Consumer<Integer> lm2 = a -> {
b = a; // compiler complains
System.out.println(b);
};
lm2.accept(20);
我了解如果我在代码段1中使用arr
重新初始化new Integer[]{1}
会导致错误,但我更有兴趣理解为什么代码段1不会导致任何错误?
答案 0 :(得分:3)
不同之处在于间接等级的数量:
arr
已修复,arr[1]
不是Integer
对象,您尝试在作业b=a
中进行更改。这是不允许的。请注意,此行为不是特定于数组的:任何可变对象都可用于实现间接。例如,您可以使用AtomicInteger
,这是可设置的:
AtomicInteger b = new AtomicInteger(10);
Consumer<Integer> lm2 = a -> {
b.set(a); // compiler complains
System.out.println(b);
};
lm2.accept(20);
答案 1 :(得分:1)
Java lambdas要求你在lambda中引用的任何变量必须有效最终 - 也就是说,你不能修改变量所持有的值。
当你只创建一个普通的Integer
时,它是一个常规值类型(自动装箱) - 分配给它会更改该值并且不允许。
但是,当你将Integer
包装在一个数组中时,你并没有修改变量本身的内容,因为它是对数组的引用 - 你要修改它对它进行引用。
答案 2 :(得分:1)
嗯,问题是Integer是一个Object引用,它的引用可以改变。
另一方面,当你有一个数组时,它是内存中一组固定的地址,无法更改(这就是为什么数组是固定长度的)。因此,您只能更改数组中的值而不是其引用。
lambda将在稍后调用,因此编译器希望您将其设置为final,以确保您不会更改对它的引用。