【发布时间】:2011-02-08 04:17:08
【问题描述】:
像这样在 Java 中遍历列表是否会更慢:
for (int i=0;i<list.size();i++) {
.. list.get(i)
}
相对于:
for (Object o: list) {
... o
}
【问题讨论】:
标签: java
像这样在 Java 中遍历列表是否会更慢:
for (int i=0;i<list.size();i++) {
.. list.get(i)
}
相对于:
for (Object o: list) {
... o
}
【问题讨论】:
标签: java
众所周知,随机和顺序的区别 * 访问经常是模糊的。例如,一些 List 实现 * 如果它们变得巨大但恒定,则提供渐近线性访问时间 * 在实践中的访问时间。这样的 List 实现 * 一般应该实现这个接口。根据经验,一个 * 列表实现应该实现这个接口,如果, * 对于类的典型实例,此循环: *
* for (int i=0, n=list.size(); i * 运行速度比这个循环快: * * for (迭代器 i=list.iterator(); i.hasNext(); ) * i.next(); * *【讨论】:
为该问题创建了一个microbenchmark,并惊讶地发现 for-each 的运行速度比索引循环快 2 到 3 倍。我唯一的解释是 for-each 版本可能不需要由 ArrayList.get(int index) 进行的范围检查。
对于非常小的列表(10 个元素),结果大致相同。对于 100 个元素,for-each 速度提高 1.5 倍,对于 10000-100000 个元素,速度提高 2x-3 倍。
测试是在随机数据集上运行的,最后校验和正在被验证,因此 JIT 校验不太可能发生在这些数据集上。
【讨论】:
我假设你是出于好奇而问的 并且不会引用 Knuth(某人 可能会)。
我相信,一旦您的代码被编译,它就不会产生任何影响。它确实在之前有所不同(示例 2 更具可读性和简洁性),因此请选择第 2 条,其余的不要关心。
只要我的 2 美分
编辑
请注意,每次循环运行时,sn-p 编号 1 中的代码都会计算 list.size(),这可能会比编号 2 更慢
又一次编辑
我必须仔细检查一下,Joshua Bloch 建议使用 for each 循环(参见 Effective Java 的第 46 项)。我相信这会结束各种讨论。谢谢乔希! :)
【讨论】:
我没有仔细研究所有 List 实现的 get() 的代码,所以也许我会写一些 FUD。我了解到的是,在 for 循环中使用 get(i) 将导致每次循环运行时一遍又一遍地对整个列表进行迭代。使用迭代器(就像增强的 for 循环一样)只会将迭代器移动到下一个列表元素,而不会再次迭代整个列表。
我的结论是使用迭代器或增强的 for 循环应该更高效,因为使用 get() 会导致复杂性 O(n^2) 而不是 O(n)。
【讨论】:
可能会有所不同。
如果 List 实现也实现了 java.util.RandomAccess(就像 ArrayList 一样),那么在交互器上使用它的 get() 方法会更快。
如果它没有实现 java.util.RandomAccess(例如,LinkedList 没有),那么使用迭代器会快得多。
但是,只有当您使用包含数千个(可能是分散的)对象或不断遍历的列表(就像对表示数字向量的列表对象执行大量数学运算一样)时,这才有意义。
【讨论】:
没有。当列表也实现时会更快(或者应该更快):RandomAccess(就像 ArrayList 和 LinkedList 一样)。
但是,您应该始终使用后者:
for( Object o: list ) {
}
只有在您有大量证据表明您在使用它时遇到性能问题时才切换到前者(例如,您分析了您的应用程序,因此您认为这是改进这部分代码的一个点)。
如果不这样做,如果您的应用程序需要,您可能无法在以后的重构中切换您的实现(因为您将被绑定到 for( int i = 0 ; i < list.size(); i++ ) 成语)。
【讨论】:
根据While loop, For loop and Iterator Performance Test – Java 中的基准测试和JavaRanch 问题“is using ArrayList.iterator() is faster than looping ArrayList in for loop?”,迭代器实际上有点慢。
我仍然倾向于可读性,除非我对整个应用程序进行了基准测试并发现该循环是我的瓶颈。
【讨论】:
每次迭代检查大小确实会增加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);
}
但这本质上并不重要。出于可读性考虑,请使用您问题中的第二个。
【讨论】:
普通列表的性能应该没有任何明显差异。
对于链表,迭代器会快很多,尤其是对于大列表。
【讨论】:
ArrayList”。