性能:在 Java 中遍历列表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2642004/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Performance: Iterating through a List in Java
提问by syker
Is it slower to iterate through a list in Java like this:
像这样在 Java 中遍历列表是否更慢:
for (int i=0;i<list.size();i++) {
.. list.get(i)
}
as opposed to:
与:
for (Object o: list) {
... o
}
采纳答案by Pablo Fernandez
I assume you ask out of pure curiosity and won't cite Knuth (somebody probably will).
我假设您纯粹是出于好奇而询问并且不会引用 Knuth(可能有人会引用)。
I believe that once your code gets compiled, it doesn't make a difference. It doesmake a difference before(example 2 is a lot more readable and concise), so go for number 2 and do not care about the rest.
我相信,一旦您的代码被编译,它就没有任何区别。它之前确实有所不同(示例 2 更具可读性和简洁性),因此请选择数字 2,不要关心其余部分。
Just my 2 cents
只是我的 2 美分
EDIT
编辑
Note your code in snippet number 1 calculates list.size()
every time the loop runs, that could make it even slower than number 2
请注意,list.size()
每次循环运行时,代码段 1 中的代码都会计算,这可能使它比代码 2 更慢
YET ANOTHER EDIT
另一个编辑
Something I had to double check, Joshua Bloch recommends using for each
loops (see item 46 of Effective Java). I believe that ends all kinds of discussions. Thanks Josh! :)
我必须仔细检查一下,Joshua Bloch 建议使用for each
循环(参见Effective Java的第46 项)。我相信这结束了各种讨论。谢谢乔希!:)
回答by SLaks
There shouldn't be any noticeable differences in performance for normal lists.
正常列表的性能不应有任何明显差异。
For linked lists, the iterator will be substantially faster, especially for large lists.
对于链表,迭代器会快很多,特别是对于大列表。
回答by Jonathon Faust
Checking the size every iteration does add i
operations, but it's not a big impact on performance.
检查每次迭代的大小确实会增加i
操作,但对性能没有太大影响。
By that, I mean there is a minor difference between
我的意思是,两者之间存在细微差别
int lsize = myList.size();
for(int i=0; i < lsize; i++)
{
Object o = myList.get(i);
}
Versus:
相对:
for(int i=0; i < myList.size(); i++)
{
Object o = myList.get(i);
}
But it essentially doesn't matter. Use the second one from your question for readability, among other reasons.
但这基本上没有关系。出于可读性等原因,请使用问题中的第二个。
回答by Bill the Lizard
According to benchmark tests in While loop, For loop and Iterator Performance Test – Javaand the JavaRanch question "is using ArrayList.iterator() is faster than looping ArrayList in for loop?" the iterator is actually a bit slower.
根据While 循环、For 循环和迭代器性能测试中的基准测试– Java和 JavaRanch 问题“使用 ArrayList.iterator() 比在 for 循环中循环 ArrayList 更快?”迭代器实际上有点慢。
I'd still favor readability unless I'd benchmarked my entire application and found that loop to be my bottleneck, though.
不过,除非我对整个应用程序进行了基准测试并发现该循环是我的瓶颈,否则我仍然倾向于可读性。
回答by OscarRyz
No. It is faster (or should be faster) when the list also implements: RandomAccess(as ArrayList does and LinkedList doesn't).
不。当列表还实现时它更快(或应该更快):RandomAccess(如 ArrayList 和 LinkedList 没有)。
However, you should always use the latter :
但是,您应该始终使用后者:
for( Object o: list ) {
}
and only switch to the former if your have substantial evidence that you're having a performance issue using it (for instance, you profile your application and as result you see as a point for improvement this section of code).
并且只有在您有充分证据表明您在使用它时遇到性能问题时才切换到前者(例如,您分析了您的应用程序,因此您将这部分代码视为改进点)。
By not doing so, you risk not being able to switch your implementation in a later refactoring if your application requires it (because you would be tied to the for( int i = 0 ; i < list.size(); i++ )
idiom).
如果不这样做,如果您的应用程序需要,您可能无法在以后的重构中切换您的实现(因为您将被绑定到for( int i = 0 ; i < list.size(); i++ )
习惯用法)。
回答by luis.espinal
THERE CAN BE A DIFFERENCE.
可能会有不同。
If a List implementation also implements java.util.RandomAccess (like ArrayList does), then it is just about faster to use its get() method over an interator.
如果 List 实现也实现了 java.util.RandomAccess(就像 ArrayList 那样),那么使用它的 get() 方法而不是交互器会更快。
If it does not implement java.util.RandomAccess (for example, LinkedList does not), then it is substantially faster to use an iterator.
如果它没有实现 java.util.RandomAccess(例如 LinkedList 没有实现),那么使用迭代器要快得多。
However, this only matter if you are using lists containing thousands of (possibly scattered) objects or that are constantly traversed (as if performing copious amounts of math on List objects representing numerical vectors.)
但是,这仅在您使用包含数千个(可能是分散的)对象或不断遍历的列表时才重要(就像对表示数值向量的 List 对象执行大量数学运算一样。)
回答by jham
I didn't look myself into the code of get()
of all List implementations so maybe what I will write is some FUD. What I have learned is that using the get(i)
in for loop will result in an iteration over the whole list over and over again each loop run. Using an Iterator (like enhanced for loop does) will just move the iterator the the next list element without iterating the whole list again.
我没有仔细get()
研究所有 List 实现的代码,所以我可能会写一些 FUD。我学到的是,使用get(i)
in for 循环将导致在每次循环运行时一遍又一遍地遍历整个列表。使用迭代器(就像增强的 for 循环那样)只会将迭代器移动到下一个列表元素,而不会再次迭代整个列表。
My conclusion is that using iterators or the enhanced for loop should be more performant since using get()
will result in complexity O(n^2)
instead of O(n)
.
我的结论是,使用迭代器或增强的 for 循环应该更高效,因为使用get()
会导致复杂性O(n^2)
而不是O(n)
.
回答by Andrey Chaschev
Created a microbenchmarkfor the question and was surprised to see for-each runing 2x-3x faster than an indexed loop. The only explanation I have is that for-each version might not require range checks which are made by ArrayList.get(int index).
为该问题创建了一个微基准测试,并惊讶地发现 for-each 的运行速度比索引循环快 2-3 倍。我唯一的解释是 for-each 版本可能不需要由 ArrayList.get(int index) 进行的范围检查。
For very small lists (10 elements) the result was about the same. For 100 elements for-each is 1.5x faster, for 10000-100000 elements it is faster 2x-3x times.
对于非常小的列表(10 个元素),结果大致相同。对于 100 个元素,for-each 快 1.5 倍,对于 10000-100000 个元素,它快 2x-3 倍。
The tests are run on a random dataset and checksums are being verified at the end, so JIT chearing is very unlikely to take place in these.
测试在随机数据集上运行,最后验证校验和,因此在这些情况下不太可能发生 JIT 校验。
回答by Gaurav
It is recognized that the distinction between random and sequential * access is often fuzzy. For example, some List implementations * provide asymptotically linear access times if they get huge, but constant * access times in practice. Such a List implementation * should generally implement this interface. As a rule of thumb, a * List implementation should implement this interface if, * for typical instances of the class, this loop: *
人们认识到随机访问和顺序访问之间的区别通常是模糊的。例如,一些 List 实现 * 如果它们变得巨大,则提供渐近线性的访问时间,但实际上 * 访问时间是恒定的。这样的 List 实现 * 一般应该实现这个接口。作为一个经验法则,一个 * List 实现应该实现这个接口,如果,* 对于类的典型实例,这个循环: *
* for (int i=0, n=list.size(); i < n; i++) * list.get(i); ** 比这个循环运行得更快:*
* for (Iterator i=list.iterator(); i.hasNext(); ) * i.next(); **