Java:为什么Java不能在lambda表达式的封闭范围内自动"finalize"局部变量?



我将其理解为函数编程的标准部分。。我的问题是,为什么编译器不能在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();
}

}

失败。。。"在封闭范围中定义的局部变量i必须是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函数永远不会修改最终确定的变量

好吧,如果变量i实际上是final,那么编译器实际上会这样做。

public static void main( String args[] )
{
int i = 5;
IntStream.range(0, 10).mapToLong( j-> i * j ).sum();
}

然而,对于第二个赋值i = 6;,您使它不是"有效的最终赋值",这表明您实际上希望它是可变的。

那么,在这种情况下,编译器为什么要制作变量的最终副本,尽管您发出信号希望它是可变的呢?

但是,如果lambda被异步传递到某个使用它的地方(即,它可以在当前函数结束后运行),并且在创建lambda后修改函数范围中的变量i,该怎么办?

int i = 5;
i = 6;
useLambdaAsynchronously( j-> i * j );
i = 7;

lambda仍然会为i捕获值6,但i(应该是同一个变量,因为您只声明了一个i)现在在另一个作用域中具有值7。这是不一致的,因为程序员应该期望单个变量一次有一个值。如果lambda稍后运行,它仍然会为i使用值6,即使7之前已经分配给i

为了避免这个问题,编译器需要确保变量没有在lambda中赋值,并且在创建lambda之后,变量没有在原始函数范围中赋值。但这会导致这样的情况,即允许在函数的早期进行赋值,但不允许在同一函数的后期进行赋值(仅仅因为它已被lambda捕获),这可能也会让程序员感到惊讶。为了简单起见,Java只是不允许在任何地方进行赋值。

最新更新