Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In a java enhanced for loop, is it safe to assume the expression to be looped over will be evaluated only once?

Tags:

java

In the following:

for (String deviceNetwork : deviceOrganizer.getNetworkTypes(deviceManufacturer)) {
    // do something
}

Is it safe to assume that deviceOrganizer.getNetworkTypes(deviceManufacturer) will be called only once?

like image 423
morgancodes Avatar asked Apr 21 '10 21:04

morgancodes


People also ask

What is the main advantage of an enhanced for loop?

MAJOR BENEFIT: To sum up, the enhanced for loop offers a concise higher level syntax to loop over a list or array which improves clarity and readability.

What is true of classes that can be used with the enhanced for loop?

The enhanced for loop (sometimes called a "for each" loop) can be used with any class that implements the Iterable interface, such as ArrayList . Here is the previous program, now written using an enhanced for loop. The program does the same thing as the previous program.


3 Answers

Yes, absolutely.

From section 14.14.2 of the spec:

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
}

(The alternative deals with arrays.)

Note how Expression is only mentioned in the first part of the for loop expression - so it's only evaluated once.

like image 138
Jon Skeet Avatar answered Oct 17 '22 18:10

Jon Skeet


Yes, give it a try:

public class ForLoop {
    public static void main( String [] args ) {
        for( int i : testData() ){
            System.out.println(i);
        }
    }
    public  static int[] testData() {
        System.out.println("Test data invoked");
        return new int[]{1,2,3,4};
    }
}

Output:

$ java ForLoop
Test data invoked
1
2 
3
4
like image 33
OscarRyz Avatar answered Oct 17 '22 17:10

OscarRyz


To complement what's been said and verify that the spec is doing what it says, let's look at the generated bytecode for the following class, which implements the old and new style loops to loop over a list returned by a method call, getList():

public class Main {
    static java.util.List getList() { return new java.util.ArrayList(); }
    public static void main(String[] args) {
        for (Object o : getList()) {
            System.out.print(o);
        }
        for (java.util.Iterator itr = getList().iterator(); itr.hasNext(); ) {
            Object o = itr.next(); System.out.print(o);
        }
    }
}

Relevant parts of the output:

   0:   invokestatic    #4; //Method getList
   3:   invokeinterface #5,  1; //InterfaceMethod java/util/List.iterator
   8:   astore_1
   9:   aload_1
   10:  invokeinterface #6,  1; //InterfaceMethod java/util/Iterator.hasNext
   15:  ifeq    35
   18:  aload_1
   19:  invokeinterface #7,  1; //InterfaceMethod java/util/Iterator.next
   24:  astore_2
   25:  getstatic   #8; //Field java/lang/System.out
   28:  aload_2
   29:  invokevirtual   #9; //Method java/io/PrintStream.print
   32:  goto    9
   35:  invokestatic    #4; //Method getList
   38:  invokeinterface #10,  1; //InterfaceMethod java/util/List.iterator
   43:  astore_1
   44:  aload_1
   45:  invokeinterface #6,  1; //InterfaceMethod java/util/Iterator.hasNext
   50:  ifeq    70
   53:  aload_1
   54:  invokeinterface #7,  1; //InterfaceMethod java/util/Iterator.next
   59:  astore_2
   60:  getstatic   #8; //Field java/lang/System.out
   63:  aload_2
   64:  invokevirtual   #9; //Method java/io/PrintStream.print
   67:  goto    44
   70:  return

This shows that the first loop (0 to 32) and the second (35-67) are identical.
The generated bytecode is exactly the same.

like image 1
JRL Avatar answered Oct 17 '22 16:10

JRL