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

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (14)

我惊讶地发现以下Java代码片段编译并运行:

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

其中listOfNumbers是一个整数数组。

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

提问于
用户回答回答于

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

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

为什么要使用像这样的最终循环变量的唯一原因是如果你需要在匿名内部类中关闭它。

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();
        }
    }
}

循环变量在执行时不在Runnable的范围内,只有在它被实例化时。没有final关键字,最终运行时,循环变量对Runnable不可见。即使这样,它对所有Runnables来说都是相同的值。

顺便说一句,大约10年前,你可能看到在局部变量上使用final的速度非常小(在极少数情况下)。很长一段时间情况并非如此。现在使用final的唯一原因是允许你使用这样的词法关闭。

当你编写代码时,你会为两个观众这样做。首先是计算机,只要它在语法上是正确的,就会对你做出的任何选择感到满意。第二个是面向未来的读者(通常是你自己),这里的目标是传达代码的“意图”,而不会遮掩代码的“功能”。应尽可能少地使用语言特征,以减少歧义。

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

扫码关注云+社区