问题描述
在Java中我有以下代码
In Java I have the following code
List<Integer> myList = new ArrayList<>();
for (int i=0;i<9;i++) {
myList.add(i);
}
Integer sum = 0;
myList.forEach(i -> {
sum = sum + i; // does not compile, sum needs to be final or effectively final
});
for(int i : myList) {
sum = sum + i; //runs without problems
}
我的问题是,为什么我无法从 lambda 内部更改 sum 的值?它与下面的 for 循环完全相同,还是我错了?有趣的是,如果我将 main 方法之外的 Integer sum 声明为静态,它也能正常工作.谁能解释我为什么?
My question is, why is it exactly that I cannot change the value of sum from within the lambda? It does the exact same thing as the for loop down below, or am I wrong? Interesting is also the fact that if I declare the Integer sum outside of the main method as static, it works as well. Can anyone explain me why?
在另一个类似的问题Java 8 是否支持闭包中,答案似乎是成为:
In another similar question Does Java 8 support closures, the answer seems to be :
它是向后兼容性和项目资源限制的结合.
但是,如果我将 sum 设为数组或在 main 之外声明它,我仍然无法理解为什么它会起作用.我还想了解 myList.forEach 和下面的 for 循环之间有什么区别,为什么一个有效而另一个无效.
However I still cannot understand why it works if I make sum an array or if I declare it outside of main. I would also like to understand what is the difference between the myList.forEach and the for loop below, why the one works and the other one doesn't.
推荐答案
尝试:
final Integer[] sum = new Integer[1];
sum[0] = 0;
myList.forEach(i -> {
sum[0] = sum[0] + i; // does not compile, sum needs to be final or effectively final
});
因为 lambda 实际上是用于初始化匿名类(并覆盖方法)的语法糖.
Since lambda is actually a syntactic sugar for initializing an anonymous class (and overriding a method).
就像你写的一样:
final Integer[] sum = new Integer[1];
sum[0] = 0;
myList.forEach(new Consumer() {
public void accept(Integer element) {
sum[0] = sum[0] + element;
}
});
来自外部作用域并在内部作用域内使用的变量必须是最终的(在本例中为 sum
).这仅仅是因为 Java 不支持闭包.因此,必须将外部变量标记为 final.由于 Integer 本身是不可变的(如果您将其声明为 final,则不能再更改它),因此您必须使用包装器对象或数组(就像我所做的那样).
The variable that comes from outer scope and that you use within inner scope must be final (in this example sum
). That is simply because Java does not support closures. Therefore, outer variable must be marked as final. Since Integer itself is immutable (if you declare it final, you cannot change it anymore), you have to use a wrapper object or an array (as I did).
您可以在这里找到更多有用的信息:
You can find more useful info here:
这篇关于Java - 从 lambda 中更改最终变量的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!