Iterators in Java


public interface Iterable
{
  Iterator iterator();
}


public interface Iterator
{
  boolean hasNext()
  Object next();
  void remove();
}
Falls somewhere between the .NET iterator and the Python iterator. hasNext() returns true if there are more elements, while next() advances then returns the element just gone. The iterator is position between elements. It's really neither fish nor fowl - there's no clear distinction between Command and Query. In .NET MoveNext tries to move and tells us if we succeeded. Here hasNext tells us if we can move. The Java iterator provides no way to query the current state of the iterator. It's bonkers.

remove is a new wrinkle - it removes the element returned by the most recent call to next from the collection. Except when it isn't allowed, in which case it throws an UnsupportedOperationException.

This is Java's second go. Java 1.1 has an Enumeration which has boolean hasMoreElements() and Object nextElement. Iterator appears to have been introduced to reduce typing and add the remove method. I am unconvinced by remove, because I don't think it's a proper thing for an iterator to be doing. It's a mutating operation on the underlying collection, which is unrelated to the act of traversing the collection. That's implicitly admitted by the fact that remove might not actually work.

Of the efforts we've looked at, I think this is the weakest. If you were given this to look at in a code review you'd send it back. It's neither fish nor fowl. It has elements of the Python iterator, in the way the next() method works, but it's not intended to by used in the "hidden" way the Python iterator is. It looks like a bit like the .NET iterator, but works in a strange way. next() operates almost entirely by side-effect. It's all about side effects. It doesn't really point at an element - it points to the gaps between them. It's all a bit designed on the hoof. The Enumerator interface works in the same way, so why the duplication? To add remove? It's a pretty poor reason. I suspect that it seemed useful at the time it was written.

Java5 brings the for each construct as a language keyword. Java convention says that language stuff lives in the java.lang. Consequently the Iterable interface lives in java.lang, but it returns a java.util.Iterator. The initial proposal did suggest a java.lang.ReadOnlyIterator (ie Iterator without the remove), but that was dropped because (apparently) it couldn't be implemented without causing code compiled pre-5 to break at runtime.

So all in all, I think it's a bit of a mess. So why do I give a toss? Why should you give a toss? Why are we even here?

I'm going to present a few examples, mainly in Java. That's partly because I wrote the original talk using Java, partly because everyone can read Java, and partly because despite their cack-handed implementation, Iterators, as defined by the Java library, can be used to do some cool and useful stuff. And if you can do cool and useful stuff in Java, you can do it any language. No, really.