我理解这是函数式编程的标准部分。我的问题是为什么编译器不能在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变量答案 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只是不允许在任何地方进行分配。