Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will this code be evaluated on every iteration?

I have this for-each-loop:

for (Component c : container.getComponents()) {
    // Loop code
}

Is getComponents called on every iteration? Does it make sense to call getComponents before the look and only work on a cached array?

like image 459
Daniel Rikowski Avatar asked Nov 28 '22 06:11

Daniel Rikowski


2 Answers

No, getComponents() will only be called once.

It's the equivalent of:

for (Iterator<Component> iterator = container.getComponents().getIterator();
     iterator.hasNext(); )
{
    Component c = iterator.next();
    ...
}

From section 14.14.2 of the Java Language Specification:

The enhanced for statement has the form:

EnhancedForStatement:

for ( VariableModifiersopt Type Identifier: Expression) Statement

The Expression must either have type Iterable or else it must be of an array type (§10.1), > or a compile-time error occurs. The scope of a local variable declared in the FormalParameter part of an enhanced for statement (§14.14) is the contained Statement

The meaning of the enhanced for statement is given by translation into a basic for statement.

If the type of Expression is a subtype of Iterable, then let I be the type of the expression Expression.iterator(). The enhanced for statement is equivalent to a basic for statement of the form:

for (I #i = Expression.iterator(); #i.hasNext(); ) {
   VariableModifiersopt Type Identifier = #i.next();
   Statement
}
like image 114
Jon Skeet Avatar answered Nov 29 '22 20:11

Jon Skeet


getComponents will be called once, and will return an Iterator. This iterator will then be called using next() and hasNext() methods.

Update Here's a bit more detail in attempt to out Skeet Jon Skeet on this answer.

The following program shows how the call to iterator is made once, even though there are three items in the collection.

public static void main(String[] args) {
    List<String> list = new ArrayList<String>() {
        public java.util.Iterator<String> iterator() {
            System.out.println("iterator() called");
            return super.iterator();
        };
    };
    list.add("a");
    list.add("b");
    list.add("c");

    for (String s : list) {
        System.out.println(s);
    }
}

Output:

iterator() called
a
b
c

If you run this through a Java decompiler, you'll find the following code:

    String s;
    for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(s))
        s = (String)iterator.next();

Addtionally, since we know from the JLS 14.14.1 that the first section of a for statement is only executed once, we can rest assured that iterator method won't be called multiple times.

like image 44
brianegge Avatar answered Nov 29 '22 20:11

brianegge