关于性能和优化的问题

gre*_*561 2 java

这是多么低效:

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

void foo(){
    for(Object o: getList()){
       do something with o;
    }
}
Run Code Online (Sandbox Code Playgroud)

与此相比:

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

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

SJu*_*n76 6

for(Object o: getList()) {
Run Code Online (Sandbox Code Playgroud)

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


NPE*_*NPE 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

字节码为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
Run Code Online (Sandbox Code Playgroud)

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

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