根据Java语言规范§14.14.2,增强for循环的变量必须在循环本地。换句话说,它将编译为:
for
for (State state : State.values()) { // do something for each state }
但这不是:
State state; for (state: State.values()) { // do something for each state }
JLS没有为这种语言设计选择提供任何依据。我可以看到如果通过final或通过注释修改了局部变量的原因,为什么必须出现类型名称,但是我不明白为什么不允许在其他地方声明的变量的裸名。是否有人对为什么施加此限制有任何见解?
final
编辑
到目前为止,有几个答案似乎表明,循环之外发生的事情是按这种方式设计语言的原因。也许仔细研究一下JLS所说的话,就能弄清楚为什么我没有这样的说服力。考虑下面的循环,State枚举在哪里:
State
for (State state : State.values()) { // ... }
State.values() 是一个数组,因此根据JLS,循环在功能上等同于:
State.values()
State[] a = State.values(); for (int i = 0; i < a.length; i++) { State state = a[i]; // ... }
现在显然可以编写出后面的循环:
State state; State[] a = State.values(); for (int i = 0; i < a.length; i++) { state = a[i]; // ... }
从概念上讲,该最后一个(完全合法的)循环可以用作for上面第二个增强循环(未编译的循环)的功能等效项。
类似地,如果stateList是Iterable<State>(不是数组),则此循环:
stateList
Iterable<State>
for (State state : stateList) { // ... }
在功能上等同于:
for (Iterator<State> iterator = stateList.iterator(); iterator.hasNext(); ) { State state = iterator.next(); // ... }
像以前一样,后面的循环可以这样写:
State state; for (Iterator<State> iterator = stateList.iterator(); iterator.hasNext(); ) { state = iterator.next(); // ... }
同样,这 可以 用作(非法)的功能等效项:
State state; for (state : stateList) { // ... }
在每种情况下,当循环退出时,的值state都定义得很好(如果没有用的话)。同样,与常规循环一样,for使用未定义的裸变量名称(例如,行State state;丢失或超出范围)的增强型循环可能会在编译时捕获。那么从语言设计的角度来看,这是什么问题呢?语言设计者为何将这种结构定为非法?
state
State state;
一种好处/理由是局部变量不会污染您的代码。让我给出一个普通的循环示例(出于类比,这不是一个确切的例子,因此没有迭代器使用):
int i; for(i=0;i<10;i++) do...something int j; for(j=0; i<10; j++) do...something
现在,在上面的代码中,如果仔细观察,您将发现一个潜在的错误。i已被错误地用于循环遍历的循环中j。
i
j
因此,增强型循环尝试通过在本地创建变量来确保安全,从而可以避免上述问题。