我正在研究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
}
}
答案 0 :(得分:4)
有效的最终规则仅适用于局部变量而非全局变量,因此,当您改变全局变量时,第一个场景没有编译错误。
如果它有助于捕获,可以将实例变量看作捕获最终的本地变量 this ,这样就没有编译错误。
本书 Java-8 in Action 对此限制有一个有效的解释,如下:
你可能会问自己为什么局部变量有这些 限制。首先,实例和实例之间存在关键差异 局部变量在幕后实现。实例变量 存储在堆上,而局部变量存在于堆栈中。如果 lambda可以直接访问局部变量而lambda是 在一个线程中使用,然后使用lambda的线程可以尝试访问 分配变量的线程之后的变量 取消分配它。因此,Java实现了对自由局部变量的访问 作为访问它的副本而不是访问原始变量。
如果仅为本地变量分配,则没有区别 因此限制了。其次,这种限制也令人沮丧 变异外部变量的典型命令式编程模式。
答案 1 :(得分:4)
我们往往忘记instanceCounter
实际上是this.instanceCounter
,您正在捕捉this
,这是有效的,有效的最终结果。至于为什么这是必要的,答案显然是here