性能:通过Java中的List进行迭代

时间:2010-04-15 00:45:24

标签: java

以这样的方式迭代Java中的列表是否较慢:

for (int i=0;i<list.size();i++) {
    .. list.get(i)
}

而不是:

for (Object o: list) {
    ... o
}

9 个答案:

答案 0 :(得分:58)

  

我假设你出于纯粹的好奇心   并且不会引用Knuth(有人   可能会)。

我相信一旦你的代码被编译,它就没有什么区别。 确实之前产生差异(示例2更具可读性和简洁性),所以请选择2号并不关心其余部分。

只需2美分

修改

请注意,每次循环运行时,您在第1个代码段中的代码会计算list.size(),这可能会使其比第二个更慢

另一个编辑

我必须仔细检查,Joshua Bloch建议使用for each循环(参见Effective Java的第46项)。我认为这结束了各种讨论。谢谢Josh! :)

答案 1 :(得分:7)

普通名单的表现不应有任何明显差异。

对于链表,迭代器将大大加快,特别是对于大型列表。

答案 2 :(得分:4)

为这个问题创建了一个microbenchmark,并且惊讶地看到 - 每次运行比索引循环快2x-3x。我唯一的解释是for-each版本可能不需要由ArrayList.get(int index)进行范围检查。

对于非常小的列表(10个元素),结果大致相同。对于100个元素 - 每个元素快1.5倍,对于10000-100000元素,速度快2倍-3倍。

测试是在一个随机数据集上运行的,并且最后会验证校验和,因此在这些测试中不太可能发生JIT的伤害。

答案 3 :(得分:3)

根据While loop, For loop and Iterator Performance Test – Java中的基准测试和JavaRanch问题“is using ArrayList.iterator() is faster than looping ArrayList in for loop?”,迭代器实际上有点慢。

我仍然喜欢可读性,除非我对整个应用程序进行基准测试,并发现循环是我的瓶颈。

答案 4 :(得分:3)

没有。当列表也实现时,它更快(或者应该更快):RandomAccess(如ArrayList所做,而LinkedList则不然)。

但是,你应该总是使用后者:

 for( Object o: list ) {
 }

如果您有充分的证据表明您在使用它时遇到性能问题(例如,您对应用程序进行了分析,结果您认为这部分代码的改进点),则只切换到前者。

如果不这样做,您可能无法在以后的重构中切换您的应用程序,如果您的应用程序需要它(因为您将与for( int i = 0 ; i < list.size(); i++ )习语绑定。)

答案 5 :(得分:3)

可能存在差异。

如果List实现也实现了java.util.RandomAccess(就像ArrayList那样),那么在交互器上使用它的get()方法要快得多。

如果它没有实现java.util.RandomAccess(例如,LinkedList没有),那么使用迭代器的速度要快得多。

但是,这只有在使用包含数千个(可能是分散的)对象的列表或者经常遍历的列表时(例如,在表示数字向量的List对象上执行大量数学运算)。

答案 6 :(得分:2)

每次迭代检查大小都会添加i次操作,但这对性能影响不大。

据此,我的意思是

之间存在细微差别
int lsize = myList.size();
for(int i=0; i < lsize; i++)
{
   Object o = myList.get(i);
}

对战:

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

但它基本上没关系。除了其他原因之外,请使用问题中的第二个来提高可读性。

答案 7 :(得分:0)

我没有看到所有List实现的get()代码,所以也许我要写的是一些FUD。我学到的是在for循环中使用get(i)将导致在每个循环运行中反复遍历整个列表。使用迭代器(如增强for for循环)只会将迭代器移动到下一个列表元素,而无需再次迭代整个列表。

我的结论是使用迭代器或增强的for循环应该更高效,因为使用get()会导致复杂性O(n^2)而不是O(n)

答案 8 :(得分:0)

人们认识到随机和顺序之间的区别  *访问通常是模糊的。例如,一些List实现  *如果它们变得巨大但不变,则提供渐近线性访问时间  *实践中的访问时间。这样的List实现  *通常应该实现此接口。一般来说,一个  *列表实现应实现此接口,如果,  *对于类的典型实例,此循环:  *

 *     for (int i=0, n=list.size(); i < n; i++)
 *         list.get(i);
 * 
 *运行速度比此循环快:  *
 *     for (Iterator i=list.iterator(); i.hasNext(); )
 *         i.next();
 * 
 *