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:
List<String> text;
...
for (String text : text) {...}
So, the same name is used for the String and the List within the for-each.
This is of course not very wise to do, but after following my nosiness before renaming it, I saw that the above code compiles fine with JDK 8, but gives the below error with JDK 7:
error: for-each not applicable to expression type
for (String text : text) {
^
required: array or java.lang.Iterable
found: String
1 error
I know that changes were made to several parts in this area within the JDK - but can someone enlighten me on why exactly this behaviour occurs?
Update: Since I got some comments about different behaviour, here's a full sample class:
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"));
}
}
}
And here's the compile process and output (Windows 7 64bit):
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>
Conclusion: I was so puzzled why my IDE (which uses 8) didn't complain about twice the same name in one statement - but now it is clear that it is not one statement. I really wonder why this point has so long been in place if the JLS states otherwise. But anyway, thanks for the insights I have received and the great answers (which made it hard for me to pick the best one).
Iterating over an array in JavaIf you only want to iterate over elements from an array or a collection e.g. a list or a set then use enhanced for loop, it's convenient and less error-prone, but if you want more control over the iteration process then use traditional for loop.
For a low number of iterations (100-1000), the enhanced for loop seems to be much faster with and without JIT. On the contrary with a high number of iterations (100000000), the traditional loop is much faster.
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
.
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…
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With