Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between for each and traditional for loop in Java in terms of shadowing?

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?

like image 751
Koray Tugay Avatar asked Apr 04 '17 17:04

Koray Tugay


People also ask

What are the difference between the Java forEach and traditional for loop?

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.

Which is faster traditional for loop or forEach in Java?

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.

What is the advantage of using forEach over traditional for loop?

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.


2 Answers

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.

like image 151
T.J. Crowder Avatar answered Oct 25 '22 08:10

T.J. Crowder


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.

like image 42
John Bollinger Avatar answered Oct 25 '22 08:10

John Bollinger