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

时间:2017-03-02 19:12:01

标签: java lambda final

我刚刚看到this question,显然很明显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)));

2 个答案:

答案 0 :(得分:5)

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

  

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

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

答案 1 :(得分:0)

我不确定这是否是答案,但在Java的文档中,它说明了以下内容:

  

对有效最终变量的限制禁止访问动态变化的局部变量,其捕获可能会引入并发问题。与最终限制相比,它减少了程序员的文书负担。

我从中理解的是,当您将lambda表达式传递给方法时,该表达式不应导致并发问题,因为此方法可以由多个线程同时使用,并且使用非最终变量可能会导致竞争条件

文档页面,如果您想自己阅读并获得更多信息:http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27.2