一尘不染

为什么增强的for循环的局部变量必须是局部的?

java

根据Java语言规范§14.14.2,增强for循环的变量必须在循环本地。换句话说,它将编译为:

for (State state : State.values()) {
    // do something for each state
}

但这不是:

State state;
for (state: State.values()) {
    // do something for each state
}

JLS没有为这种语言设计选择提供任何依据。我可以看到如果通过final或通过注释修改了局部变量的原因,为什么必须出现类型名称,但是我不明白为什么不允许在其他地方声明的变量的裸名。是否有人对为什么施加此限制有任何见解?

编辑

到目前为止,有几个答案似乎表明,循环之外发生的事情是按这种方式设计语言的原因。也许仔细研究一下JLS所说的话,就能弄清楚为什么我没有这样的说服力。考虑下面的循环,State枚举在哪里:

for (State state : State.values()) {
    // ...
}

State.values() 是一个数组,因此根据JLS,循环在功能上等同于:

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上面第二个增强循环(未编译的循环)的功能等效项。

类似地,如果stateListIterable<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;丢失或超出范围)的增强型循环可能会在编译时捕获。那么从语言设计的角度来看,这是什么问题呢?语言设计者为何将这种结构定为非法?


阅读 246

收藏
2020-12-03

共1个答案

一尘不染

一种好处/理由是局部变量不会污染您的代码。让我给出一个普通的循环示例(出于类比,这不是一个确切的例子,因此没有迭代器使用):

int i;
for(i=0;i<10;i++)
  do...something

int j;
for(j=0; i<10; j++)
  do...something

现在,在上面的代码中,如果仔细观察,您将发现一个潜在的错误。i已被错误地用于循环遍历的循环中j

因此,增强型循环尝试通过在本地创建变量来确保安全,从而可以避免上述问题。

2020-12-03