9

The Javadoc for ListIterator says:

A ListIterator has no current element; its cursor position always lies between the element that would be returned by a call to previous() and the element that would be returned by a call to next().

Why was Java's ListIterator implemented to point between elements rather than at a current element? It seems that this makes client code less readable when it has to repeatedly call getNext(), getPrevious(), so I assume there must be a good reason for the choice.

As a side note, I just wrote a little library called peekable-arraylist that extends ArrayList, Iterator, and ListIterator that provides a peekAtNext() and peekAtPrevious() methods implemented like:

  @Override public synchronized T peekAtNext() {
     T t = next();
     previous();
     return t;
  }
2

1 Answer 1

12

As far as I can tell, the reason can be found in the part of javadoc you didn't quote (emphasis below mine):

An iterator for lists that allows the programmer to traverse the list in either direction, modify the list during iteration...

You see, the intended purpose is to allow usage while list is being modified. Possible modifications apparently include removal of the elements.

Now think of what would happen if we remove an element that would be current() for iterator - assuming that iterator would have a notion of current element? In this context, the way to implement it without a notion of current element makes pretty good sense to me - because that way, iterator does not have to worry about elements removal.


It is important to note that javadoc does not require interface implementations to be thread safe.

  • Because of that, one should not expect correct handling of modifications done from different threads - for that, implementation would have to provide additional means to synchronize access, guarantee visibility etc as specified by Java Memory Model per JSR 133.

What ListIterator is capable of, is handling modifications done from the same thread when iterating. Not all the iterators are like that, ConcurrentModificationException javadocs specifically warn about this:

...Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception...

8
  • 1
    It also means you don't need a separate insertBefore and insertAfter, although that's not as big an issue as a remove. Mar 3, 2012 at 22:04
  • 1
    So is the issue that one could concurrently remove and access the current element? Wouldn't this be the equivalent issue as concurrently calling next()? remove() would be synchronized as would getCurrent(). Am I missing something? Mar 3, 2012 at 22:20
  • @glenviewjeff that's a very good observation. I also wonder how CME could be handled there - the very stated intent to allow for modifications raises concerns like that. Guess I need to dig deeper. I'm 99.99% sure it's not intended as thread safe, maybe it can only handle concurrent mods done from the same thread (not all iterators are capable of that, you know)
    – gnat
    Mar 3, 2012 at 22:25
  • If you're interested, see my edit. I implemented and packaged an extension to ArrayList to accomplish this. Mar 3, 2012 at 23:20
  • @glenviewjeff interesting. In your implementation, are next() and previous() also sync'd? I ask because if not, then other thread can "drill" some unexpected move right into the middle of your current(), making it behave not quite like client would expect... Methods like add() probably would need sync, too
    – gnat
    Mar 3, 2012 at 23:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.