为什么实例变量忽略“Lambda表达式中使用的变量必须是最终的或有效的最终”警告

时间:2017-12-27 21:16:52

标签: lambda java-8 java-stream

我正在研究java 8流,我唯一的问题是理解lambdas是为什么lambdas中的有效最终警告被忽略的实例(和静态)变量。我似乎无法在网上找到任何参考,因为大多数网页只会谈论“有效最终”的定义。

public class LambdaTest {

    int instanceCounter = 0;

    public void method() {
        int localCounter = 0;
        instanceCounter = 5; //Re-assign instance counter so it is no longer effectively final

        Stream.of(1,2,3).forEach(elem -> instanceCounter++); //WHY DOES THE COMPILER NOT COMPLAIN HERE
        Stream.of(1,2,3).forEach(elem -> localCounter++); //Does not compile because localCounter is not effectively final
    }
}

2 个答案:

答案 0 :(得分:4)

为什么局部变量的编译错误?

有效的最终规则仅适用于局部变量而非全局变量,因此,当您改变全局变量时,第一个场景没有编译错误。

如果它有助于捕获,可以将实例变量看作捕获最终的本地变量 this ,这样就没有编译错误。

为什么会有这样的限制?

本书 Java-8 in Action 对此限制有一个有效的解释,如下:

  

你可能会问自己为什么局部变量有这些   限制。首先,实例和实例之间存在关键差异   局部变量在幕后实现。实例变量   存储在堆上,而局部变量存在于堆栈中。如果   lambda可以直接访问局部变量而lambda是   在一个线程中使用,然后使用lambda的线程可以尝试访问   分配变量的线程之后的变量   取消分配它。因此,Java实现了对自由局部变量的访问   作为访问它的副本而不是访问原始变量。

     

如果仅为本地变量分配,则没有区别   因此限制了。其次,这种限制也令人沮丧   变异外部变量的典型命令式编程模式。

答案 1 :(得分:4)

我们往往忘记instanceCounter实际上是this.instanceCounter,您正在捕捉this,这是有效的,有效的最终结果。至于为什么这是必要的,答案显然是here