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这样的兄弟语言的广告优势。
看起来很好。 你想在你的匿名类中使用循环变量的值 ,而循环变量显然不是最终的(因为它的值会改变)。
创建新的最终局部变量是一个很好的解决方案。