Java for-each on getter

时间:2010-06-04 12:13:52

标签: java gwt foreach getter

如果javac按照我的想法行事,以下几行将产生相同的效果:

for (Object o: getObjects()) {}
List<Object> os = getObjects(); for (Object o: os) {}

是这样吗?或者它可能是特定于实现的?如果是这样:有人知道GWT吗?

5 个答案:

答案 0 :(得分:7)

表现将完全相同。

Java编译器通过调用循环对象上的Iterator方法,将每个循环转换为围绕iterator()对象的循环。
因此,实际列表实例仅使用一次。 (致电iterator()

答案 1 :(得分:7)

来自Java语言规范:

  

14.14.2 The enhanced for statement

     

增强的for语句有   形式:

EnhancedForStatement:
        for ( VariableModifiersopt Type Identifier: Expression) Statement
     

Expression必须具有类型   Iterable或者它必须是   数组类型(第10.1节),或编译时   发生错误。

     

声明的局部变量的范围   在FormalParameter中的一部分   增强的for声明(§14.14)是   包含的声明

     

增强型for的含义   声明是通过翻译给出的   一个基本的for陈述。

     

如果 Expression 的类型是a   Iterable的子类型,然后让 I 成为   表达式的类型   表达。 iterator()。增强的for语句是等效的   到...的基本for陈述   形式:

for (I #i = Expression.iterator(); #i.hasNext(); ) {

        VariableModifiersopt Type Identifier = #i.next();
   Statement
}
     

#i 是编译器生成的   与任何不同的标识符   其他标识符(编译器生成的   或者在其他方面)在范围内(§6.3)   在增强的点   声明发生。

如您所见, Expression 仅在for循环表达式的第一部分中提及,因此仅评估一次。所以你的两条线会产生相同的性能。

答案 2 :(得分:5)

从纯Java角度来看,这些答案似乎都是正确的。此外,如果可以,GWT编译器实际上将进一步重写增强的for循环,在生成JavaScript之前进入常规for循环。所以它实际上最终会看起来像:

for (int i = 0; i < getObjects().size(); i++) {
  Object o = getObjects().get(i);
  // ...
}

原因?如果从未引用List iterator对象,则可以将其声明为死代码,并且不会在JavaScript中重写,从而导致较小的下载大小。这种优化应该对代码的实际执行没有任何影响。

请参阅今年的Google I / O中的Optimizing apps with the GWT compiler,了解GWT编译器为减少JS大小而做的其他疯狂事情的​​更多细节。

答案 3 :(得分:3)

从实际角度来看,您可以检查两个字节码并进行比较:

 m1()V
   L0
    ALOAD 0
    INVOKEVIRTUAL it/funge/Console.getObjects()Ljava/util/List;
    INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator;
    ASTORE 2
    GOTO L1
   L2
   FRAME FULL [it/funge/Console T java/util/Iterator] []
    ALOAD 2
    INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object;
    ASTORE 1
   L1
   FRAME SAME
    ALOAD 2
    INVOKEINTERFACE java/util/Iterator.hasNext()Z
    IFNE L2
   L3
    RETURN

m2()V
   L0
    ALOAD 0
    INVOKEVIRTUAL it/funge/Console.getObjects()Ljava/util/List;
    ASTORE 1
   L1
    ALOAD 1
    INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator;
    ASTORE 3
    GOTO L2
   L3
   FRAME FULL [it/funge/Console java/util/List T java/util/Iterator] []
    ALOAD 3
    INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object;
    ASTORE 2
   L2
   FRAME SAME
    ALOAD 3
    INVOKEINTERFACE java/util/Iterator.hasNext()Z
    IFNE L3
   L4
    RETURN

它们是相同的,唯一的区别是你的第二个片段有两个独立的部分来加载List然后获得迭代器。这也将消耗更多类的本地人,事实上它还有ALOADASTORE以上,它用于通过两行代码存储getObjects结果它直接使用它的片段..

答案 4 :(得分:2)

没有区别。 foreach构造只从对象中获取Iterator。这就是为什么它必须实现Iterable接口。