Java 中的闭包 - 捕获的值 - 为什么会出现这种意外结果?
我想我在JavaScript中遇到了这种经典情况。
通常程序员会期望下面的代码打印“Peter”,“Paul”,“Mary”。
但事实并非如此。谁能确切地解释为什么它在Java中以这种方式工作?
此 Java 8 代码编译正常,并打印 3 次“Mary”。
我想这是一个如何在内心深处实现的问题,
但是......这是否表明底层实现是错误的?
import java.util.List;
import java.util.ArrayList;
public class Test008 {
public static void main(String[] args) {
String[] names = { "Peter", "Paul", "Mary" };
List<Runnable> runners = new ArrayList<>();
int[] ind = {0};
for (int i = 0; i < names.length; i++){
ind[0] = i;
runners.add(() -> System.out.println(names[ind[0]]));
}
for (int k=0; k<runners.size(); k++){
runners.get(k).run();
}
}
}
相反,如果我使用增强的for循环(在添加Runnables时),则会捕获正确的(即所有不同的)值。
for (String name : names){
runners.add(() -> System.out.println(name));
}
最后,如果我使用经典的for循环(在添加Runnables时),那么我会收到一个编译错误(这是非常有意义的,因为变量不是最终的或有效的最终的)。i
for (int i = 0; i < names.length; i++){
runners.add(() -> System.out.println(names[i]));
}
编辑:
我的观点是:为什么不捕获的值(在我添加Runnables时它的价值)?当我执行 lambda 表达式时,这应该无关紧要,对吧?我的意思是,好吧,在具有增强的for循环的版本中,我也稍后执行Runnables,但正确/不同的值是在更早(添加Runnables时)捕获的。names[ind[0]]
换句话说,为什么Java在捕获值时并不总是具有按值/快照语义(如果我可以这样说的话)?难道它不是更干净,更有意义吗?