Enhanced for loop compiling fine for JDK 8 but not 7

生来就可爱ヽ(ⅴ<●) 提交于 2019-11-30 16:51:01
Holger

While the reasoning, using the specified translation from the enhanced for loop to the traditional for loop, used by other answers is correct, there is an explicit specification about the scopes:

§6.3. Scope of a Declaration

The scope of a local variable declared in the FormalParameter part of an enhanced for statement (§14.14.2) is the contained Statement.

(direct link)

Thus, the scope of the variable does not include the Expression of the enhanced for loop…

You can verify that this hasn’t changed, compared to Java 7 and Java 6, though both (I tried Java 6 javac) exhibit the contradicting behavior.

So this change in the compiler behavior is the fix of an old bug…

This should actually compile fine for JDK 7 and 8.

Quoting JLS section 14.14.2 (which is the same for the Java 7 specification):

The enhanced for statement is equivalent to a basic for statement of the form:

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

Rewriting the enhanched for loop with Iterator

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

becomes

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

Then, quoting example 6.4.1 of the JLS:

A similar restriction on shadowing of members by local variables was judged impractical, because the addition of a member in a superclass could cause subclasses to have to rename local variables. Related considerations make restrictions on shadowing of local variables by members of nested classes, or on shadowing of local variables by local variables declared within nested classes unattractive as well.

As such, there is no compile-time error here because no restriction is made when shadowing a member variable by a local variable, which is the case here: the local variable String text is shadowing the member variable List<String> text.

I would say it is a compiler bug in the particular version of the Java 7 compiler that you are using.

The earlier text is a field, and it is legal for the text local declared in the for statement to shadow a field.

Then we look at what the for loop means. According to the JLS,

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

is equivalent to

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

As you can see the inner text is not in-scope for the text.iterator() expression.


I tried searching the Oracle Java Bugs Database, but couldn't find anything that matched this scenario.

Although I think the other answers are correct, let me be devil's advocate and offer the opposite view.

Obviously JDK 7 parses the foreach loop in such a way that the variable 'text' is also in scope after the ':'. To test this, I wrote the following method. It compiles and runs just fine in Java 1.7:

public static void main(String[] args) {
    for (String text : new String[] {text = "hello", text, text, text})
        System.out.println(text);
}

Although others have said this is a bug in jdk 1.7 (and it probably is), I couldn't find anywhere in the JLS that specifically says the variable just declared is not in scope after the ':'. If it's not a bug, then Java 8 breaks compatibility.

Your build server may be compiling using a different jdk than your local machine. (Not just a different version number, but a completely different implementation.) Eclipse is one that uses its own compiler, I believe to facilitate its code hot-swapping.

Using the same name for the collection and the element ought to raise problems anywhere, but I have heard of and occasionally noticed Eclipse tolerating things that the Sun/Oracle JDK won't.

This compiled fine for me. I'm using the Java 8 JDK, on Netbeans, on a 64 bit machine (Windows 7).

I believe this is a localization issue related to your IDE or compiler. I used your exact example, the output being

false
true
false

There was a warning given, stating that it is possible, but not recommended to hide a field with a local variable.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!