简体   繁体   English

在java增强的for循环中,可以安全地假设要循环的表达式只会被评估一次吗?

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

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? 假设deviceOrganizer.getNetworkTypes(deviceManufacturer)只被调用一次是否安全?

Yes, absolutely. 是的,一点没错。

From section 14.14.2 of the spec : 规范的第14.14.2节

If the type of Expression is a subtype of Iterable, then let I be the type of the expression Expression.iterator(). 如果Expression的类型是Iterable的子类型,那么让我成为表达式Expression.iterator()的类型。 The enhanced for statement is equivalent to a basic for statement of the form: 增强的for语句相当于表单的基本for语句:

 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. 注意Expression是如何仅在for循环表达式的第一部分中提到的 - 所以它只被评估一次。

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() : 为了补充已经说过的内容并验证规范是否正在执行它所说的内容,让我们看一下下面类生成的字节码,它实现了旧的和新的样式循环来循环遍历方法调用返回的列表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 . 这表明第一个循环(0到32)和第二个循环(35-67)是相同的
The generated bytecode is exactly the same . 生成的字节码完全相同

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM