我一直在阅读有关Java使用lambda时如何处理闭包的信息。 我了解到,当使用原始值时,因为将值复制到lambda中,所以在声明lambda之后修改此类原语不会对lambda产生任何影响,并且还可能会在执行lambda时释放局部变量
强制将自由变量设为最终变量是有道理的,但是使用对象时可以绕过此限制所施加的行为。
就像下面的代码一样,尝试修改 n 会导致编译错误:
public static Runnable referenceClosure(){
int n = 9595;
Runnable r = () -> System.out.println(n);
//n++; //would cause compilation error.
return r;
}
但这可以通过以下方法绕过:
public static Runnable classClosure(){
IntHolder holder = new IntHolder(9898);
Runnable r = () -> System.out.println(holder.value);
holder.value++;
return r;
}
static class IntHolder{
Integer value;
IntHolder(Integer value) {
this.value = value;
}
}
一旦可运行文件被执行,这将导致打印9899。
但是,在以下情况下:
public static Runnable referenceParamClosure(Integer n){
Runnable r = () -> System.out.println(n);
//n++; //would cause compilation error.
return r;
}
声明lambda后增加 n 会导致编译错误。 由于原始包装器是不可变的,因此增加 n 会创建一个Integer的新实例并重新分配n的指针,但不会重新分配在lambda中使用的指针。
知道为什么会这样吗?