for循环中的最终计数器?

我有这个代码:

List r = new ArrayList(); for(int i = 0; i < 10; i++) { r.add(new Runnable() { @Override public void run() { System.out.println(i); } }); } 

它显然无法编译,因为i需要最终在匿名类中使用。 但我不能把它作为最终决定,因为事实并非如此。 你会怎么做? 一个解决方案是复制它,但我认为可能有更好的方法:

  List r = new ArrayList(); for(int i = 0; i < 10; i++) { final int i_final = i; r.add(new Runnable() { @Override public void run() { System.out.println(i_final); } }); } 

编辑只是为了说清楚,我在这里使用Runnable为例子,问题是关于匿名类,这可能是其他任何东西。

我认为您的解决方案是最简单的方法。

另一种选择是将内部类的创建重构为为您完成它的工厂函数,然后您的循环本身可能是干净的东西:

 List r = new ArrayList<>(); for(int i = 0; i < 10; i++) { r.add(generateRunnablePrinter(i)); } 

工厂函数可以声明一个最终参数:

 private Runnable generateRunnablePrinter(final int value) { return new Runnable() { public void run() { System.out.println(value); } }; } 

我更喜欢这种重构方法,因为它使代码更清晰,相对自我描述并且还隐藏了所有内部类管道。

随机离题:如果你认为匿名内部类等同于闭包,那么generateRunnablePrinter实际上是一个更高阶的函数。 谁说你不能用Java做函数式编程:-)

这就是IntelliJ为您解决的问题。 唯一的区别是我会这样做

 ExecutorService es = for(int i = 0; i < 10; i++) { final int i_final = i; es.execute(new Runnable() { 

(不太理想)替代方法:创建一个实现Runnable的小内部类:

 class Printer implements Runnable { private int index; public Printer(int index) { this.index = index; } public void run() { System.out.println(index); } } List r = new ArrayList<>(); for(int i = 0; i < 10; i++) { r.add(new Printer(i)); } 

你的解决方案还不错。 你可以做其他的事情,比如定义你自己的Runnable子类,并在构造函数或初始化块中用i初始化它,但在这种情况下,我认为只是在没有正当理由的情况下增加复杂性。

顺便说一句:我认为你的例子是一个合成的例子,在实践中创建一个新的Runnable只是打印一个整数似乎不是一个好主意。

我担心除了将你的计数器复制到第二个最终变量之外别无他法,并在你的匿名内部类中使用它。 这是关于闭包主题的Java的“缺陷”之一,以及像Groovy这样的兄弟语言的广告优势。

看起来很好。 你在你的匿名类中使用循环变量的 ,而循环变量显然不是最终的(因为它的值会改变)。

创建新的最终局部变量是一个很好的解决方案。