33

Is it slower to iterate through a list in Java like this:

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

as opposed to:

for (Object o: list) {
    ... o
}
zneak
  • 134,922
  • 42
  • 253
  • 328
syker
  • 10,912
  • 16
  • 56
  • 68

9 Answers9

60

I assume you ask out of pure curiosity and won't cite Knuth (somebody probably will).

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.

Just my 2 cents

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

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! :)

Pablo Fernandez
  • 103,170
  • 56
  • 192
  • 232
  • 1
    +1 Good point, compilation may give same performance even if the first one is done on a LinkedList. – Rhangaun Apr 15 '10 at 00:54
  • @Skeptic and even if it doesn't now, it surely will perform the same (or better) in a future version – Pablo Fernandez Apr 15 '10 at 00:55
  • Compilation probably will not give the (exact) same performance unless the compiler can tell that the contents of the list haven't changed. Can it do that? I don't know! The second version would be faster because it will assume the list contents don't change, I believe. The second version in the question is more like the first example in my answer. Size is assumed constant to the best of my knowledge. – Jonathon Faust Apr 15 '10 at 00:58
  • 7
    Premature optimization is **not** the root of all evil, copy/paste **is**!! – OscarRyz Apr 15 '10 at 01:04
  • 16
    How about copy-pasting prematurely optimized code ? How evil is that !! – Newtopian Apr 15 '10 at 01:30
  • 3
    With relaxation therapy you CAN prevent premature optimisation. – Rob Kielty Jun 14 '13 at 21:03
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.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
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).

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.

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.

Andrey Chaschev
  • 16,160
  • 5
  • 51
  • 68
  • More comparisons are made here: https://dzone.com/articles/iteration-over-java-collections-with-high-performa Also they use "standardised" JMH library for microbenchmarking. – Lubo Mar 17 '20 at 13:04
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.

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

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
3

No. It is faster (or should be faster) when the list also implements: RandomAccess (as ArrayList does and LinkedList doesn't).

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).

Lawrence Dol
  • 63,018
  • 25
  • 139
  • 189
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
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.

If it does not implement java.util.RandomAccess (for example, LinkedList does not), then it is substantially faster to use an iterator.

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.)

luis.espinal
  • 10,331
  • 6
  • 39
  • 55
  • Implementing RandomAccess does not guarantee get() is fast. You could write a linked list that implements RandomAccess - and it'd be slow as hell. – kibibu Apr 15 '10 at 03:28
  • 1
    @Kibiku - yes, you can code an implementation of RandomAccess ***that violates*** its interface contract agreement. There is nothing that stops at compile time from doing so for any documented interface contract. That'd be a sh*tty written or maliciously-written implementation and that's beyond the scope of what RandomAccess is supposed to provide. At some point, as an engineer, you have to draw a line in the sand, program following a design-by-contract, and make valid inferences. I'd question someone's ability to code were he/she to violate the contract of such a simple interface marker. – luis.espinal Apr 15 '10 at 13:24
  • 1
    Also, and for that matter, I could create a class that implements java.util.Map, that operates in read only mode but which silently ignores calls to put(), remove() and putAll() instead of throwing UnsupportedOperationException() (which is the expected behavior to be implemented by read-only Map instances.) Barring extreme edge cases where you need to do so, the ability to do so is a sign of not understanding the contracts implied by an interface. An interface is not just a marker or a collection of methods. They are semantic contracts that developers are supposed to follow. – luis.espinal Apr 15 '10 at 13:32
2

Checking the size every iteration does add i operations, but it's not a big impact on performance.

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.

Jonathon Faust
  • 12,396
  • 4
  • 50
  • 63
  • 2
    I wonder why it's so common to do as shown here instead of "for(int i=0,siz=myList.size(); i – Lawrence Dol Apr 15 '10 at 02:24
  • Probably because that's a premature micro-optimization and most people don't think it improves readability. The compiler should optimize away the size checks anyways, and even if it doesn't in most cases this wouldn't come close to being a bottleneck. – Brian Jan 10 '14 at 16:10
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: *

 *     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();
 * 
*
Gaurav
  • 1
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.

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).

JMax
  • 26,109
  • 12
  • 69
  • 88
jham
  • 375
  • 1
  • 6
  • As written in a previous answer, it depends on the type of the list. What you write is only true for lists that do not implement RandomAccess (e.g., for LinkedList, but not for ArrayList). – Philipp Wendler Aug 30 '11 at 07:28