Why does Java not allow foreach on iterators (only on iterables)?

The Iterable interface was created exactly for that purpose (enhanced for loop) as described in the original JSR, although the Iterator interface was already in use.

Regarding the new interfaces discussed in the JSR (note the package names):

  • java.lang.Iterable
  • java.lang.ReadOnlyIterator (proposed in JSR to be retrofitted onto java.util.Iterator though not actually done)

…the JSR says:

These new interfaces serve to prevent the dependency of the language on java.util that would otherwise result.


Because the "for" loop would be destructive to the iterator. Iterator cannot be reset (ie. moved back to the beginning) unless it implements the ListIterator subinterface.

Once you put an Iterator through a "for" loop it would no longer useable. My guess is the language designers decided that this combined with the additional special cases (of which there are already two for Iterable and arrays) in the compiler to translate this into bytecode (you couldn't reuse the same transformation as iterable) was enough of a detractor to not implement it.

When you do this yourself in the code via the iterator interface, it would at least be apparantly obvious what's going on.

With lambdas coming they could make this nice and easy:

Iterator<String> iterator = ...;
Collections.each ( iterator, (String s) => { System.out.println(s); } );

List<String> list = ...;
Collections.each ( list, (String s) => { System.out.println(s); } );

without breaking backward compatibility, and still having a relatively simple syntax. I doubt they would built methods like "each", "collect" and "map" into the different interfaces because that would break backward compatibilty, plus you'd have arrays still to deal with.


So I have a somewhat reasonable explanation now:

Short version: Because the syntax also applies to arrays, which don't have iterators.

If the syntax were designed around Iterator as I proposed, it would be inconsistent with arrays. Let me give three variants:

A) as chosen by the Java developers:

Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list) { }
Iterator<Object> iter;
while(iter.hasNext()) { Object o = iter.next(); }

The behaves the same way and is highly consistent across arrays and collections. Iterators however have to use the classic iteration style (which at least is not likely to cause errors).

B) allow arrays and Iterators:

Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list.iterator()) { }
Iterator<Object> iter;
for(Object o : iter) { }

Now arrays and collections are inconsistent; but arrays and ArrayList are very closely related and should behave the same way. Now if at any point, the language is extended to make e.g. arrays implement Iterable, it becomes inconsistent.

C) allow all three:

Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list) { }
Iterator<Object> iter;
for(Object o : iter) { }

Now if we end up in unclear situations when either someone implements both Iterable and Iterator (is the for loop supposed to get a new iterator or iterate over the current - happens easily in tree-like structures!?!). A simple tie-braker ala "Iterable beats Iterator" unfortunately won't do: it suddenly introduces runtime vs. compile time difference and generics issues.

Now suddenly, we need to pay attention to whether we want to iterate over collections/iterables or arrays, at which point we have gained very little benefits at the cost of a big confusion.

The way "for each" is in Java (A) is very consistent, it causes very little programming errors, and it allows for the possible future change of turning arrays into regular objects.

There is a variant D) that would probably also work okay: for-each for Iterators only. Preferrably by adding a .iterator() method to primitive arrays:

Object[] array;
for(Object o : array.iterator()) { }
Iterable<Object> list;
for(Object o : list.iterator()) { }
Iterator<Object> iter;
for(Object o : iter) { }

But this requires changes to the runtime environment, not just the compiler, and breaks backwards compatibility. Plus, the mentioned confusion is still present that

Iterator<Object> iter;
for(Object o : iter) { }
for(Object o : iter) { }

Only iterates over the data once.