Consider the following code snippet, I stumpled upon after some refactoring, when checkin why the build server reported a broken build but it was fine in my IDE:
<
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.
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…
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.
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.
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
.