针对 JDK 8(但不是 7)的循环编译进行了增强

2022-09-01 10:55:23

考虑以下代码片段,在经过一些重构后,我在签入时遇到了困难,为什么构建服务器报告构建损坏,但在我的IDE中很好:

List<String> text;
...
for (String text : text) {...}

因此,字符串和 for-each 中的 List 使用相同的名称。

这当然不是很明智,但是在重命名之前遵循了我的nosiness之后,我看到上面的代码在JDK 8中编译良好,但在JDK 7中给出了以下错误:

  error: for-each not applicable to expression type
        for (String text : text) {
                           ^
  required: array or java.lang.Iterable
  found:    String
1 error

我知道在JDK中对这一领域的几个部分进行了更改 - 但是有人可以启发我为什么会发生这种行为吗?


更新:由于我收到了一些关于不同行为的评论,这里有一个完整的示例类:

import java.util.Arrays;
import java.util.List;

public class Strange {

    List<String> text = Arrays.asList("Max", "Alex", "Maria");

    public static void main(String[] args) {
        new Strange().doSomething("Alex");
    }

    public void doSomething(String name) {
        for (String text : text) {
            System.out.println(text.equals("Alex"));
        }
    }

}

以下是编译过程和输出(Windows 7 64位):

C:\copy>c:\Projects\java\jdk1.7.0_79\bin\javac.exe Strange.java
Strange.java:13: error: for-each not applicable to expression type
        for (String text : text) {
                           ^
  required: array or java.lang.Iterable
  found:    String
1 error

C:\copy>c:\Projects\java\jdk1.8.0_60\bin\javac.exe Strange.java

C:\copy>

结论:我很困惑为什么我的IDE(使用8)没有在一个语句中抱怨两个相同的名称 - 但现在很明显它不是一个语句。我真的很想知道,如果JLS另有规定,为什么这一点已经存在了这么长时间。但无论如何,感谢我收到的见解和精彩的答案(这使我很难选择最好的答案)。


答案 1

这实际上应该可以很好地编译 JDK 7 和 8。

引用 JLS 第 14.14.2 节(这与 Java 7 规范相同):

增强的 for 语句等效于以下形式的基本 for 语句:

for (I #i = Expression.iterator(); #i.hasNext(); ) {
      {VariableModifier} TargetType Identifier =
          (TargetType) #i.next();
      Statement
}

重写增强的 for 循环Iterator

for (String text : text) {...}

成为

for (Iterator<String> it = text.iterator(); it.hasNext(); ) {
    String text = it.next();
}

然后,引用 JLS 的示例 6.4.1

对局部变量对成员的阴影的类似限制被认为是不切实际的,因为在超类中添加成员可能导致子类必须重命名局部变量。相关注意事项使得嵌套类成员对局部变量的阴影的限制,或者对嵌套类中声明的局部变量对局部变量的阴影的限制也没有吸引力。

因此,这里没有编译时错误,因为在局部变量阴影成员变量时没有限制,这里就是这种情况:局部变量正在隐藏成员变量 。String textList<String> text


答案 2

虽然使用从增强型循环到传统循环的指定转换(由其他答案使用)的推理是正确的,但有一个关于范围的明确规范:forfor

§6.3.声明的范围

...

在增强语句 (§14.14.2) 的 FormalParameter 部分中声明的局部变量的作用域是包含的语句for

(直接链接)

因此,变量的作用域不包括增强型循环的表达式...for

Java 7和Java 6相比,您可以验证这一点没有改变,尽管两者(我尝试过Java 6)都表现出矛盾的行为。javac

因此,编译器行为中的这种变化是对旧错误的修复...