为什么编译器拒绝访问lambda中的非final变量

Blu*_*ire 1 java lambda final

我刚看到这个问题,显然很明显Java应该拒绝访问lambda表达式体内的非final变量.为什么?

编辑:例如,我不明白为什么以下代码有害:

String[] numbers = new String[10]; // put some numerical strings in
BigInteger sum = new BigInteger("0");
numbers.forEach(n -> sum = sum.add(new BigInteger(n)));
Run Code Online (Sandbox Code Playgroud)

Dar*_*hta 5

Lambdas只是语法糖,他们被编入anonymous inner classes.匿名内部类non-final因其范围而无法使用局部变量.这是解释:

方法的局部变量存在于堆栈中,并且仅在方法的生命周期中存在.您已经知道局部变量的范围仅限于声明变量的方法.当方法结束时,堆栈帧被吹走,变量是历史记录.但即使在方法完成之后,在其中创建的内部类对象仍可能在堆上存活,例如,如果对它的引用被传递到其他代码中,然后存储在实例变量中.因为只要方法本地内部类对象,局部变量不能保证存活,内部类对象不能使用它们.除非局部变量标记为final!

礼貌:SCJP 6 Kathy Sierra和Bert Bates的学习指南

  • @puhlen:因为lambda/anonymous类实例/本地类实例可以比该函数更长,所以lambda/anonymous类实例/本地类实例在创建lambda/anonymous类实例/本地类实例时获取该变量的副本,并且lambda/anonymous类实例/本地类实例将使用自己的变量副本.所以现在有两个独立的变量副本.如果它不是最终的,则对一个副本的更改不会反映在同一变量的另一个副本中.为了防止这种情况,它必须是最终的(或者在Java 8中是有效的). (2认同)