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

Java: why java can't automatically "finalize" local variables in enclosing scope of lambda expression?

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


}

失败... "Local variable i defined in an enclosing scope must be final or effectively 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 实际上是最终的,那么编译器 实际上会这样做。

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

然而,对于第二个赋值 i = 6;,您没有 "effectively final",这表明您实际上希望它是可变的。

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

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

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

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

为避免此问题,编译器需要确保变量未在 lambda 中赋值 并且 变量在创建后未在原始函数作用域中赋值拉姆达。但这会导致允许在函数中较早的赋值,但不允许在同一函数中较晚的赋值(只是因为它已被 lambda 捕获),这也可能让程序员感到惊讶。为简单起见,Java 只是禁止在任何地方赋值。