2010-04-21 25 views
13

在以下几点:在java增强for循环中,是否可以安全地假设循环表达式仅被计算一次?

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

它是安全的假设,deviceOrganizer.getNetworkTypes(deviceManufacturer)将只有一次叫什么名字?

+3

我真心希望如此,否则我有很多重写的代码... – skaffman 2010-04-21 21:29:17

+0

可能的重复http://stackoverflow.com/questions/1618202/java-foreach-loop – 2010-04-21 21:37:01

+3

@Pascal Thivent - 是的,但我的标题更好:) – morgancodes 2010-04-21 21:39:22

回答

18

是的,绝对。

section 14.14.2 of the spec

如果表达式的类型是可迭代的子类型,则让我是 表达Expression.iterator()的类型。增强的for语句等价于一个基本为 语句的形式为:(与阵列的替代交易)

for (I #i = Expression.iterator(); #i.hasNext();) { 
     VariableModifiersopt Type Identifier = #i.next(); 
    Statement 
} 

注意如何Expression仅在的用于第一部分提到循环表达 - 所以它只被评估一次。

7

不错,不妨一试:

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}; 
    } 
} 

输出:

$ java ForLoop 
Test data invoked 
1 
2 
3 
4 
1

来补充有人说和验证规范是做什么它说,让我们来看看生成的字节码下面的类,它实现旧式和新式循环以循环方法调用返回的列表,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); 
     } 
    } 
} 

输出的相关部分:

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 

这表明第一环路(0至32)和第二(35-67)是相同
生成的字节码与完全相同。

+2

哦,人......我们**必须**看字节码吗?我们不能按照JLS的规定行事吗? – 2010-04-22 01:18:28

+0

LOL谢谢斯蒂芬,正是我在想什么。不要抨击OP,但在我看来,字节码在这种情况下无法帮助他 – 2010-04-22 02:53:54