开发者

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

开发者 https://www.devze.com 2022-12-27 22:11 出处:网络
In the following: 开发者_如何转开发for (String deviceNetwork : deviceOrganizer.getNetworkTypes(deviceManufacturer)) {

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?


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.


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


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消