Iterator VS For

Iterator vs for

First of all, there are 2 kinds of for loops, which behave very differently. One uses indices:

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

This kind of loop isn't always possible. For example, Lists have indices, but Sets don't, because they're unordered collections.

The other one, the foreach loop uses an Iterator behind the scenes:

for (Thing thing : list) {
...
}

This works with every kind of Iterable collection (or array)

And finally, you can use an Iterator, which also works with any Iterable:

for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) {
Thing t = it.next();
...
}

So you in fact have 3 loops to compare.

You can compare them in different terms: performance, readability, error-proneness, capability.

An Iterator can do things that a foreach loop can't. For example, you can remove elements while you're iterating, if the iterator supports it:

for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) {
Thing t = it.next();
if (shouldBeDeleted(thing) {
it.remove();
}
}

Lists also offer iterators that can iterate in both directions. A foreach loop only iterates from the beginning to an end.

But an Iterator is more dangerous and less readable. When a foreach loop is all you need, it's the most readable solution. With an iterator, you could do the following, which would be a bug:

for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) {
System.out.println(it.next().getFoo());
System.out.println(it.next().getBar());
}

A foreach loop doesn't allow for such a bug to happen.

Using indices to access elements is slightly more efficient with collections backed by an array. But if you change your mind and use a LinkedList instead of an ArrayList, suddenly the performance will be awful, because each time you access list.get(i), the linked list will have to loop though all its elements until the ith one. An Iterator (and thus the foreach loop) doesn't have this problem. It always uses the best possible way to iterate through elements of the given collection, because the collection itself has its own Iterator implementation.

My general rule of thumb is: use the foreach loop, unless you really need capabilities of an Iterator. I would only use for loop with indices with arrays, when I need access to the index inside the loop.

Which is more efficient, a for-each loop, or an iterator?

If you are just wandering over the collection to read all of the values, then there is no difference between using an iterator or the new for loop syntax, as the new syntax just uses the iterator underwater.

If however, you mean by loop the old "c-style" loop:

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

Then the new for loop, or iterator, can be a lot more efficient, depending on the underlying data structure. The reason for this is that for some data structures, get(i) is an O(n) operation, which makes the loop an O(n2) operation. A traditional linked list is an example of such a data structure. All iterators have as a fundamental requirement that next() should be an O(1) operation, making the loop O(n).

To verify that the iterator is used underwater by the new for loop syntax, compare the generated bytecodes from the following two Java snippets. First the for loop:

List<Integer>  a = new ArrayList<Integer>();
for (Integer integer : a)
{
integer.toString();
}
// Byte code
ALOAD 1
INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator;
ASTORE 3
GOTO L2
L3
ALOAD 3
INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object;
CHECKCAST java/lang/Integer
ASTORE 2
ALOAD 2
INVOKEVIRTUAL java/lang/Integer.toString()Ljava/lang/String;
POP
L2
ALOAD 3
INVOKEINTERFACE java/util/Iterator.hasNext()Z
IFNE L3

And second, the iterator:

List<Integer>  a = new ArrayList<Integer>();
for (Iterator iterator = a.iterator(); iterator.hasNext();)
{
Integer integer = (Integer) iterator.next();
integer.toString();
}
// Bytecode:
ALOAD 1
INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator;
ASTORE 2
GOTO L7
L8
ALOAD 2
INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object;
CHECKCAST java/lang/Integer
ASTORE 3
ALOAD 3
INVOKEVIRTUAL java/lang/Integer.toString()Ljava/lang/String;
POP
L7
ALOAD 2
INVOKEINTERFACE java/util/Iterator.hasNext()Z
IFNE L8

As you can see, the generated byte code is effectively identical, so there is no performance penalty to using either form. Therefore, you should choose the form of loop that is most aesthetically appealing to you, for most people that will be the for-each loop, as that has less boilerplate code.

Performance of traditional for loop vs Iterator/foreach in Java

Assuming this is what you meant:

// traditional for loop
for (int i = 0; i < collection.size(); i++) {
T obj = collection.get(i);
// snip
}

// using iterator
Iterator<T> iter = collection.iterator();
while (iter.hasNext()) {
T obj = iter.next();
// snip
}

// using iterator internally (confirm it yourself using javap -c)
for (T obj : collection) {
// snip
}

Iterator is faster for collections with no random access (e.g. TreeSet, HashMap, LinkedList). For arrays and ArrayLists, performance differences should be negligible.

Edit: I believe that micro-benchmarking is root of pretty much evil, just like early optimization. But then again, I think it's good to have a feeling for the implications of such quite trivial things. Hence I've run a small test:

  • iterate over a LinkedList and an ArrayList respecively
  • with 100,000 "random" strings
  • summing up their length (just something to avoid that compiler optimizes away the whole loop)
  • using all 3 loop styles (iterator, for each, for with counter)

Results are similar for all but "for with counter" with LinkedList. All the other five took less than 20 milliseconds to iterate over the whole list. Using list.get(i) on a LinkedList 100,000 times took more than 2 minutes (!) to complete (60,000 times slower). Wow! :) Hence it's best to use an iterator (explicitly or implicitly using for each), especially if you don't know what type and size of list your dealing with.

For-each vs Iterator. Which will be the better option

for-each is syntactic sugar for using iterators (approach 2).

You might need to use iterators if you need to modify collection in your loop. First approach will throw exception.

for (String i : list) {
System.out.println(i);
list.remove(i); // throws exception
}

Iterator it=list.iterator();
while (it.hasNext()){
System.out.println(it.next());
it.remove(); // valid here
}

Iterator and while-loop vs for-loop vs for-each performance for getting elements of a list

Don't think about performances. It is extremely on a mirco-management level that you would not even notice it. Besides that an Iterator is needed for iterating over a Collection. The enhanced for loop is a syntactical sugar, but it does the same as the Iterator. The only difference is that you explicitly need a Iterator to modify the Collection while looping over it. See How to avoid "ConcurrentModificationException" while removing elements from `ArrayList` while iterating it?

And lastly the range based loop is a way to limit the number of iteration while the other ones iterate over the whole Collection (except you add some conditions inside the loop block)

Java Iterator vs for loop

Why are you removing and adding, when you can simply replace the value? You should use either List.set(int index, E element), or ListIterator.set(E e).

While iterating a collection, you are generally not allowed to modify the collection, except through the iterator. The iterators of most collection objects implement fail-fast logic to prevent accidentally violating that rule. The exception are for collections specifically designed for multi-threaded concurrent access.

So, if using an Iterator, only modify through that iterator.

// Using ListIterator
public final void ricolora(Color c) {
for (ListIterator<Pixel> it = this.pixel.listIterator(); it.hasNext(); ) {
Pixel pi = it.next();
Pixel gi = new Pixel(pi.getX(), pi.getY(), c);
it.set(gi);
}
}

// Using index
public final void ricolora(Color c) {
for (int i = 0; i < this.pixel.size(); i++) {
Pixel pi = this.pixel.get(i);
Pixel gin = new Pixel(pi.getX(), pi.getY(), c);
this.pixel.set(i, gin);
}
}

The Iterator version is generally preferred, because it performs well regardless of List implementation, e.g. the index version will perform badly if the List is a LinkedList.



Related Topics



Leave a reply



Submit