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

时间:2021-02-16 22:30:37

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
}

9 个解决方案

#1


58  

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 does make 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

请注意,每次循环运行时,您在第1个代码段中的代码计算list.size(),这可能会比第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建议每个循环使用(参见Effective Java的第46项)。我认为这结束了各种讨论。谢谢乔希! :)

#2


7  

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.

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

#3


4  

Created a microbenchmark for 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).

为这个问题创建了一个微基准测试,并且惊讶地看到 - 每个运行速度比索引循环快2x-3x。我唯一的解释是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个元素 - 每个元素快1.5倍,对于10000-100000个元素,速度快2倍-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不太可能在这些中发生。

#4


3  

According to benchmark tests in While loop, For loop and Iterator Performance Test – Java and 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()比循环中的ArrayList更快吗?”迭代器实际上有点慢。

I'd still favor readability unless I'd benchmarked my entire application and found that loop to be my bottleneck, though.

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

#5


3  

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 ();>

#6


3  

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对象上执行大量数学运算一样。)

#7


2  

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.

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

#8


0  

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.

我没有看到所有List实现的get()代码,所以也许我会写的是一些FUD。我学到的是在for循环中使用get(i)将导致在每个循环运行中反复遍历整个列表。使用迭代器(如增强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)。

#9


0  

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实现应实现此接口if,*对于类的典型实例,此循环:*

 *     for (int i=0, n=list.size(); i < n; i++)
 *         list.get(i);
 * 
* runs faster than this loop: *
 *     for (Iterator i=list.iterator(); i.hasNext(); )
 *         i.next();
 * 
*

#1


58  

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 does make 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

请注意,每次循环运行时,您在第1个代码段中的代码计算list.size(),这可能会比第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建议每个循环使用(参见Effective Java的第46项)。我认为这结束了各种讨论。谢谢乔希! :)

#2


7  

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.

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

#3


4  

Created a microbenchmark for 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).

为这个问题创建了一个微基准测试,并且惊讶地看到 - 每个运行速度比索引循环快2x-3x。我唯一的解释是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个元素 - 每个元素快1.5倍,对于10000-100000个元素,速度快2倍-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不太可能在这些中发生。

#4


3  

According to benchmark tests in While loop, For loop and Iterator Performance Test – Java and 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()比循环中的ArrayList更快吗?”迭代器实际上有点慢。

I'd still favor readability unless I'd benchmarked my entire application and found that loop to be my bottleneck, though.

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

#5


3  

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 ();>

#6


3  

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对象上执行大量数学运算一样。)

#7


2  

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.

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

#8


0  

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.

我没有看到所有List实现的get()代码,所以也许我会写的是一些FUD。我学到的是在for循环中使用get(i)将导致在每个循环运行中反复遍历整个列表。使用迭代器(如增强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)。

#9


0  

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实现应实现此接口if,*对于类的典型实例,此循环:*

 *     for (int i=0, n=list.size(); i < n; i++)
 *         list.get(i);
 * 
* runs faster than this loop: *
 *     for (Iterator i=list.iterator(); i.hasNext(); )
 *         i.next();
 * 
*