Java:为什么java不能在封闭lambda表达式范围内自动“完成”局部变量?

时间:2017-10-05 16:29:01

标签: java lambda functional-programming final

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


}

失败...“我在一个封闭范围内定义的局部变量必须是最终的或有效的最终”,而编译器应该足够聪明,可以做这样的事情

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函数

永远不会修改finalized变量

2 个答案:

答案 0 :(得分:1)

好吧,如果您的变量i实际上是最终的,编译器 会实际执行此操作。

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

然而,在第二次作业i = 6;中,你不能使它成为最终的#34;,你表明你确实希望它是可变的。

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

答案 1 :(得分:0)

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

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

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

为避免此问题,编译器需要确保在lambda 中未分配变量,并且在创建lambda之后未在原始函数范围中分配变量。但是这会导致一种情况,即允许在函数中较早的赋值,但后来在同一函数中不允许(仅因为它已被lambda捕获),这对程序员来说也许是令人惊讶的。为简单起见,Java只是不允许在任何地方进行分配。