为什么是";Lambda表达式中使用的变量必须是final或有效final;忽略实例变量的警告

为什么是";Lambda表达式中使用的变量必须是final或有效final;忽略实例变量的警告,lambda,java-8,java-stream,Lambda,Java 8,Java Stream,我正在研究Java8流,唯一的问题是理解lambdas,即为什么lambdas中的有效最终警告会被忽略,例如(和静态)变量。我似乎在网上找不到任何关于它的参考资料,因为大多数网页只会讨论“有效最终”的定义 为什么局部变量会出现编译错误? 有效的最终规则只适用于局部变量,而不适用于全局变量,因此,在变异全局变量时,第一个场景没有编译错误 如果有助于捕获实例变量,则可以将其视为捕获最终的局部变量,这样就不会出现编译错误 为何会有这样的限制? 《Java-8在行动》一书对此限制有一个有效的解释,如下所

我正在研究Java8流,唯一的问题是理解lambdas,即为什么lambdas中的有效最终警告会被忽略,例如(和静态)变量。我似乎在网上找不到任何关于它的参考资料,因为大多数网页只会讨论“有效最终”的定义

为什么局部变量会出现编译错误? 有效的最终规则只适用于局部变量,而不适用于全局变量,因此,在变异全局变量时,第一个场景没有编译错误

如果有助于捕获实例变量,则可以将其视为捕获最终的局部变量,这样就不会出现编译错误

为何会有这样的限制? 《Java-8在行动》一书对此限制有一个有效的解释,如下所示:

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

如果局部变量仅指定给 一旦有了限制。第二,这一限制也阻碍了发展 变异外部变量的典型命令式编程模式


我们倾向于忘记,
instanceCounter
实际上是
这个。instanceCounter
,您正在捕获
这个
,这是非常有效的最终结果。至于为什么需要这样做,答案显然是肯定的

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
    }
}