Java:为什么Java不能在lambda表达式的封闭范围内自动“完成”局部变量?
我认为这是函数式编程的标准部分。。我的问题是为什么编译器不能在lambda语句开始之前自动将变量的副本声明为final
import java.util.stream.IntStream;
public class Example
{
public static void main( String args[] )
{
int i = 5;
i = 6;
IntStream.range(0, 10).mapToLong( j-> i * j ).sum();
}
}
失败。。。“我在封闭范围内定义的局部变量必须是final或实际上是final”,而编译器似乎应该足够聪明,可以这样做
import java.util.stream.IntStream;
public class Example
{
public static void main( String args[] )
{
int i = 5;
i = 6;
final int _i = i;
IntStream.range(0, 10).mapToLong( j-> _i * j ).sum();
}
}
编译器可以强制lambda函数永远不会修改最终确定的变量
# 1 楼答案
但是,如果lambda被传递到某个异步使用它的地方(即,它可以在当前函数结束后运行),并且在创建lambda之后修改函数范围中的变量
i
,该怎么办lambda仍然会为
i
捕获一个值6,但是i
(应该是同一个变量,因为您只声明了一个i
)现在在另一个作用域中的值为7。这是不一致的,因为程序员应该期望一个变量一次只有一个值。如果稍后运行lambda,它仍将使用i
的值6,即使之前已将7分配给i
为避免此问题,编译器需要确保在创建lambda后,未在lambda中分配变量,且未在原始函数范围中分配变量。但这将导致这样一种情况,即在函数的前面允许赋值,但在同一函数的后面不允许赋值(仅仅因为它已被lambda捕获),这也可能会让程序员感到惊讶。为了简单起见,Java只是不允许在任何地方进行赋值
# 2 楼答案
好吧,如果变量
i
实际上是最终变量,编译器实际上会这样做然而,对于第二个赋值
i = 6;
,您使它不是“有效的最终赋值”,您表明您实际上希望它是可变的那么,为什么在这种情况下,编译器应该创建变量的最终副本,尽管您发出了希望它是可变的信号