“final int i”如何在Java for循环中工作?

我惊讶地看到,下面的Java代码片段被编译和运行:

for(final int i : listOfNumbers) { System.out.println(i); } 

其中listOfNumbers是一个整数数组。

我以为最后的声明只能分配一次。 编译器是否创build一个Integer对象并更改它所引用的内容?

想象一下,简写看起来很像这样:

 for (Iterator<Integer> iter = listOfNumbers.iterator(); iter.hasNext(); ) { final int i = iter.next(); { System.out.println(i); } } 

请参阅@TravisG,了解涉及的范围规则的解释。 为什么要使用像这样的最终循环variables的唯一原因是,如果你需要closures它在一个匿名的内部类。

 import java.util.Arrays; import java.util.List; public class FinalLoop { public static void main(String[] args) { List<Integer> list = Arrays.asList(new Integer[] { 0,1,2,3,4 }); Runnable[] runs = new Runnable[list.size()]; for (final int i : list) { runs[i] = new Runnable() { public void run() { System.out.printf("Printing number %d\n", i); } }; } for (Runnable run : runs) { run.run(); } } } 

循环variables在执行时不在Runnable的范围内,仅当它​​被实例化时。 没有final关键字,最终运行时,循环variables对Runnable将不可见。 即使是这样,对于所有的Runnables也是一样的。

顺便说一句,大约10年前,你可能已经看到在局部variables上使用final(在极less数情况下)的速度提高很小。 长久以来一直没有这样的情况。 现在使用final的唯一原因是允许你使用这样的词法closures。

在回答@mafutrct:

当你编写代码的时候,你是为了两个观众。 首先是计算机,只要它在语法上是正确的,就会对你做的任何select感到满意。 第二个是面向未来的读者(通常是你自己),这里的目标是沟通代码的“意图”,而不遮盖代码的“function”。 语言特征应尽可能less的解释以减less歧义。

在循环variables的情况下,可以使用final来传达以下两件事之一:单一赋值; 或者closures。 循环的简单扫描将告诉你循环variables是否被重新分配; 然而,由于在创build闭包时交织两个执行path,可能很容易错过用于捕获variables的闭包。 当然,除非你只使用final来指示捕获的意图,在这一点上读者就会明白正在发生的事情。