This is the code I have:
class HelloWorld {
char[] foo = {'a', 'b'};
// This will compile
void foo() {
for (char foo : foo) {
}
}
// This will not compile
void bar() {
for (char foo = 0; foo < foo.length; foo++) {
}
}
}
How come foo
compiles but compiling bar
fails with:
Error: char cannot be dereferenced
What is the difference between the two loop declarations that makes loop in foo compile but bar fail?
The difference between for Loop and foreach loop is that the for loop is a general purpose control structure while the foreach loop is an enhanced for loop that is applicable only to arrays and collections.
Foreach performance is approximately 6 times slower than FOR / FOREACH performance. The FOR loop without length caching works 3 times slower on lists, comparing to arrays. The FOR loop with length caching works 2 times slower on lists, comparing to arrays.
The advantage of the for-each loop is that it eliminates the possibility of bugs and makes the code more readable. It is known as the for-each loop because it traverses each element one by one. The drawback of the enhanced for loop is that it cannot traverse the elements in reverse order.
We can see the difference by looking at JLS§14.14.2's description of how the enhanced for
works when handling an array:
The enhanced for statement is equivalent to a basic for statement of the form:
T[] #a = Expression; L1: L2: ... Lm: for (int #i = 0; #i < #a.length; #i++) { {VariableModifier} TargetType Identifier = #a[#i]; Statement }
Note how the variable is declared within the body of the loop, not the header of the loop. That is, your foo
function is like this:
void foo() {
{ // Freestanding block for scope, though not really needed as `foo` has
// nothing else in it
char[] a = foo; // T[] #a = Expression;
for (int i = 0; i < a.length; i++) {
char foo = a[i]; // {VariableModifier} TargetType Identifier = #a[#i];
}
}
}
That's why you get away with the shadowing in the enhanced for
, and not in the traditional for
, which needs to access the original array (to get its length
, to get the entry for i
, etc.).
More about the enhanced for
loop in How does the Java 'for each' loop work? and its answers.
The Java Language Specification defines the scopes of your two char foo
's differently:
The scope of a local variable declared in the ForInit part of a basic
for
statement (§14.14.1) includes all of the following:
- Its own initializer
- Any further declarators to the right in the ForInit part of the
for
statement- The Expression and ForUpdate parts of the
for
statement- The contained Statement
The scope of a local variable declared in the FormalParameter part of an enhanced
for
statement (§14.14.2) is the contained Statement.
(JLS 8, section 6.3)
That perfectly explains your observed behavior: the local foo
is in scope in the control clause of the basic for
loop (everywhere to the right of its declaration) and therefore it shadows the other foo
there, but in the enhanced for
loop its scope is only the loop statement -- it is not in scope anywhere in the loop control clause.
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