Lambdas:局部变量需要 final,实例变量不需要

2022-08-31 12:43:22

在 lambda 中,局部变量必须是最终的,但实例变量不需要。为什么会这样?


答案 1

字段和局部变量之间的根本区别在于,当 JVM 创建 lambda 实例时,将复制局部变量。另一方面,字段可以自由更改,因为对它们的更改也会传播到外部类实例(它们的范围是整个外部类,正如 Boris 在下面指出的那样)。

考虑匿名类,闭包和labmdas的最简单方法是从变量范围的角度来看;想象一下,为传递给闭包的所有局部变量添加了一个复制构造函数。


答案 2

在 lambda 项目的文档中:Lambda v4 的状态

在第7节下。变量捕获,它提到....

我们的意图是禁止捕获可变局部变量。原因是像这样的成语:

int sum = 0;
list.forEach(e -> { sum += e.size(); });

基本上是连续的;编写像这样没有争用条件的 lambda 主体是相当困难的。除非我们愿意强制(最好是在编译时)这样的函数无法逃脱其捕获线程,否则此功能可能会导致比解决的更多的麻烦。

编辑:

这里要注意的另一件事是,当您在内部类中访问局部变量时,局部变量在内部类的构造函数中传递,这不适用于非最终变量,因为非最终变量的值可以在构造后更改。

而在实例变量的情况下,编译器传递类的引用,类的引用将用于访问实例变量。因此,在实例变量的情况下不需要它。

PS :值得一提的是,匿名类只能访问最终的局部变量(在JAVA SE 7中),而在Java SE 8中,您也可以有效地访问lambda内部的最终变量以及内部类。


推荐