是否会在每次迭代时评估此代码?

时间:2009-10-09 13:22:19

标签: java performance loops

我有这个for-each-loop:

for (Component c : container.getComponents()) {
    // Loop code
}

每次迭代都会调用getComponents吗?在外观之前调用getComponents并且仅在缓存的数组上工作是否有意义?

5 个答案:

答案 0 :(得分:17)

不,getComponents()只会被调用一次。

相当于:

for (Iterator<Component> iterator = container.getComponents().getIterator();
     iterator.hasNext(); )
{
    Component c = iterator.next();
    ...
}

来自section 14.14.2 of the Java Language Specification

  

增强的for语句具有以下形式:

     

EnhancedForStatement:

for ( VariableModifiersopt Type Identifier: Expression) Statement
     

Expression必须具有Iterable类型,否则它必须是数组类型(第10.1节),&gt;或发生编译时错误。   在FormalParameter部分中声明的局部变量的范围是增强的   声明(第14.14节)是包含的声明

     

增强的for语句的含义是通过翻译成基本的for来给出的   言。

     

如果Expression的类型是Iterable的子类型,那么让我成为它的类型   表达Expression.iterator()。增强的for语句相当于一个基本的   for表格声明:

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

答案 1 :(得分:10)

getComponents将被调用一次,并将返回一个Iterator。然后使用next()和hasNext()方法调用此迭代器。

更新以下是针对此答案尝试输出 Skeet Jon Skeet的更多细节。

以下程序显示了对iterator的调用是如何进行一次的,即使集合中有三个项目。

public static void main(String[] args) {
    List<String> list = new ArrayList<String>() {
        public java.util.Iterator<String> iterator() {
            System.out.println("iterator() called");
            return super.iterator();
        };
    };
    list.add("a");
    list.add("b");
    list.add("c");

    for (String s : list) {
        System.out.println(s);
    }
}

输出:

iterator() called
a
b
c

如果您通过Java反编译器运行它,您将找到以下代码:

    String s;
    for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(s))
        s = (String)iterator.next();

另外,由于我们从JLS 14.14.1知道for语句的第一部分只执行一次,我们可以放心,迭代器方法不会被多次调用。

答案 2 :(得分:3)

Java LanguageSpecification 14.14.2说:

  

EnhancedForStatement:
  for ( VariableModifiersopt Type Identifier: Expression) Statement

     

如果Expression的类型是Iterable的子类型,那么让我成为表达式Expression.iterator()的类型。增强的for语句相当于表单的基本语句:

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

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

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

因此表达式仅被评估一次(在初始化期间)。

答案 3 :(得分:2)

  

每个人都会调用getComponents吗?   迭代?

没有。 Java的foreach循环基于Iterable接口,相当于此代码

Iterator<Component> i = container.getComponents().iterator
while(i.hasNext()) {
    Component c = i.next();
    // loop body goes here
}

唯一的区别是Iterator是隐藏的。

答案 4 :(得分:0)

我原本以为在编译时,它会被转换为循环的“长手”,就像使用for(int i = 0 ....

一样

foreach循环不仅仅是编程节省时间,实际的字节码转换与“长手”一样吗?

简而言之,只应调用getComponent()一次