关于性能和优化的问题

时间:2011-07-26 08:01:09

标签: java

效率如何:

List<Object> getList(){
    return new LinkedList<Object>();
}

void foo(){
    for(Object o: getList()){
       do something with o;
    }
}

与之相比:

List<Object> getList(){
    return new LinkedList<Object>();
}

void foo(){
    List<Object>  os = getList();
    for(Object o: os){
       do something with o;
    }
}

4 个答案:

答案 0 :(得分:6)

for(Object o: getList()) {

getList()是一个表达式,它被计算一次,并保留其结果(列表的引用iterator)。如果你担心这个代码在每次迭代时调用getList(),那就不是真的(如果是,如果每次迭代以新列表开始时列表至少有一个元素,它将是一个无限循环,在0元素。)

答案 1 :(得分:5)

没有任何可察觉的差异。

我编译了以下代码:

import java.util.LinkedList;
import java.util.List;

public class Test1 {

    static List<Object> getList(){
        return new LinkedList<Object>();
    }

    void process(Object o) {}

    void foo1(){
        for(Object o: getList()){
            process(o);
        }
    }

    void foo2(){
        List<Object>  os = getList();
        for(Object o: os){
            process(o);
        }
    }
}

foo1foo2的字节码如下:

void foo1();
  Code:
   0:   invokestatic    #26; //Method getList:()Ljava/util/List;
   3:   invokeinterface #28,  1; //InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
   8:   astore_2
   9:   goto    24
   12:  aload_2
   13:  invokeinterface #34,  1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
   18:  astore_1
   19:  aload_0
   20:  aload_1
   21:  invokevirtual   #40; //Method process:(Ljava/lang/Object;)V
   24:  aload_2
   25:  invokeinterface #42,  1; //InterfaceMethod java/util/Iterator.hasNext:()Z
   30:  ifne    12
   33:  return

void foo2();
  Code:
   0:   invokestatic    #26; //Method getList:()Ljava/util/List;
   3:   astore_1
   4:   aload_1
   5:   invokeinterface #28,  1; //InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
   10:  astore_3
   11:  goto    26
   14:  aload_3
   15:  invokeinterface #34,  1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
   20:  astore_2
   21:  aload_0
   22:  aload_2
   23:  invokevirtual   #40; //Method process:(Ljava/lang/Object;)V
   26:  aload_3
   27:  invokeinterface #42,  1; //InterfaceMethod java/util/Iterator.hasNext:()Z
   32:  ifne    14
   35:  return

正如您自己看到的,两个循环的字节码是相同的。唯一的区别是foo2在开始时将列表引用存储并加载到局部变量中。

有人可能会争辩说,更好的优化编译器可以完全消除os,为两个函数生成相同的代码。

答案 2 :(得分:4)

这样:

List<Object>  os = getList();

只创建一个引用并且不复制实际数据,速度差异可以忽略不计,可能是不存在的,因为它可能是相同的字节码。

答案 3 :(得分:0)

事实上,前者在理论上更有效率,因为在后者中还有一个参考创建。

然而,这可以忽略不计(实际上可以忽略不计)。