通过程序遍历LinkedList时,我一直在检查每个 vs 迭代器的的效果:
public class ListTraversePerformance {
public static void main(String... args){
List<String> list = new LinkedList<String>();
for(int i=0;i<100000;i++){
list.add("Any String" + i);
}
Iterator i = list.iterator();
String x;
long t1 = System.currentTimeMillis();
for(String j: list){
x = j;
}
long t2 = System.currentTimeMillis();
while(i.hasNext()){
x= (String)i.next();
}
long t3 = System.currentTimeMillis();
System.out.print((t2-t1) + " " + (t3-t2));
}
}
我得到的输出每次都不同,即有时第一个循环快速运行,有时第二个循环。
我的问题:
我认为每个循环的应该比第二个 Iterator 慢。我认为在for each
循环中,每次复制O(n^2)
与O(n)
Iterator
的复杂性相比,链表应该从头开始遍历。我对么?如果是,那么为什么结果不像我期望的那样......
答案 0 :(得分:3)
两者几乎相同,并且它们都是O(n),因为每个元素只被迭代一次。不重复迭代。
每个循环使用引擎盖下的迭代器。它是用于迭代实现Iterable的对象的语法糖,后者又创建了一个迭代器。因此,当我说两者几乎相同时,我的意思是字面意思。
微观基准测试很难做到正确。最大的问题是,我们最终认为我们正在计划一件事,但实际上我们正在计划其他事情;为了理解真正发生的事情,需要花费大量的精力去挖掘它们。阅读以下相关文章的答案,它将解释为什么时间变化如此之多以及如何使用它。 Why are floating point operations much faster with a warmup phase?。这个问题的SO与基于自己的基准测试几乎相同,只使用浮点运算而不是列表迭代。
快速摘要是1)JVM通过解释器开始执行代码,并动态优化代码的热区域,2)GC和其他后台进程可能会干扰,有些可能在JVM中,有些可能在外部JVM。