当前位置: 首页 > 面试题库 >

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

林鸿彩
2023-03-14
问题内容

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


问题答案:

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

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

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

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

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



 类似资料:
  • 问题内容: 我有一个关于变量范围的相当简单的问题。 我对增强型循环很熟悉,但是我不明白为什么我应该声明一个新变量来保留每个元素。一个例子可以澄清我的问题: 那为什么要声明这个新变量呢?毕竟在for循环内是可访问的。我不想使用任何先前的值,只是不想声明一个新变量。(我猜想对于其他可迭代项,使用相同变量可能会更快)。 我想这就是增强型循环的构建方式,但这不会破坏整个范围的想法吗? 上述行为引起了一个问

  • 我甚至不确定这段代码是否能做任何事情,即使它有效,但我不知道该怎么做才能摆脱“从内部类引用的局部变量必须是最终的或有效的最终”错误消息,该错误消息显示在以“fireballRight[i]”开头的三行上。 任何指导将不胜感激,谷歌似乎并没有帮助我。

  • 问题内容: 我什至不知道此代码即使能正常工作也不会做任何事情,但是我不知道该怎么做才能摆脱“从内部类引用的局部变量必须是最终的或实际上是最终的”错误消息,该错误消息在以“ fireballRight [i]”开头的三行中显示。 任何指导将不胜感激,谷歌似乎没有帮助我这一点。 问题答案: 您尚未显示所有代码,但我怀疑添加了以下内容: 在循环内使用而不是将其用作数组的索引应该可以修复错误。 另外,如@

  • 这个问题在这里已经有了答案: > 为什么匿名类只能访问最终变量? 为什么对于实例变量[重复]忽略“Lambda表达式中使用的变量必须是final或实际上是final”警告 “lambda在start方法参数被垃圾回收后才能运行”是什么意思? 为什么要复制?

  • 问题内容: 我正在尝试解决一个任务(我对Java还是很陌生),并且已经花了很多资源来解决此冲突,但是仍然无法解决(注意:Tuna是我的Scanner变量) } 结果是:线程“ main” java.lang.Error中的异常:未解决的编译问题:重复的局部变量计数 我应该解决的问题是: 编写程序以读取一个数字并将所有数字从1汇总到该数字。例如,如果用户键入6,则输出为21(1 + 2 + 3 +

  • 这个程序是我的类的最终赋值,我在弄清楚为什么我收到错误“从内部类引用的局部变量必须是最终的或实际上是最终的”时遇到了问题。该程序正在运行并发线程来对#的数组进行排序,然后找到该数组的高值和低值。当我在没有并发的情况下创建它时,我没有这个错误。我正在努力确定在哪里最终确定高变量和低变量。 这是产生错误的代码块。如果我使int高=数字[0];或int-low=数字[0];final,然后我得到一个错误