繁体   English   中英

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

[英]Performance: Iterating through a List in Java

在Java中迭代遍历列表是否更慢:

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

而不是:

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

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

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

只需2美分

编辑

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

再来一次编辑

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

普通列表的性能不应有任何明显差异。

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

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

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

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

根据While循环中的基准测试,For循环和Iterator性能测试 - Java和JavaRanch问题“ 正在使用ArrayList.iterator()比在循环中循环ArrayList更快吗? ”迭代器实际上有点慢。

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

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

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

 for( Object o: list ) {
 }

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

如果你的应用程序需要它,你就有可能无法在以后的重构中切换你的实现(因为你将被绑定到for( int i = 0 ; i < list.size(); i++ ) idiom) 。

可能有所不同。

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

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

但是,这仅限于使用包含数千个(可能是分散的)对象的列表或者经常遍历的列表(就像在表示数字向量的List对象上执行大量数学运算一样。)

检查每次迭代的大小确实会增加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);
}

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

人们认识到随机和顺序*访问之间的区别通常是模糊的。 例如,某些List实现*提供渐近线性访问时间,如果它们变大,但实际上是恒定的访问时间。 这样的List实现*通常应该实现这个接口。 根据经验,* List实现应实现此接口if,*对于类的典型实例,此循环:*

*     for (int i=0, n=list.size(); i < n; i++)
 *         list.get(i);
 *
*比这个循环运行得更快:*
\n  * for(Iterator i = list.iterator(); i.hasNext();)\n  * i.next();\n  * 
*

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM