为什么Java中不允许以下lambda代码?

时间:2019-07-04 12:05:49

标签: java closures

我一直在阅读有关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中使用的指针。

知道为什么会这样吗?

0 个答案:

没有答案