Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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;
  }
share|improve this question
2  
There is a peekable iterator in the Guava library code.google.com/p/guava-libraries –  kevin cline Mar 4 '12 at 6:32
    
Thanks Kevin! I posted a follow-up question to this on SO: Is it possible to use Guava's ForwardingListIterator with a PeekingIterator? –  glenviewjeff Mar 4 '12 at 14:38
add comment

1 Answer

up vote 9 down vote accepted

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

share|improve this answer
1  
It also means you don't need a separate insertBefore and insertAfter, although that's not as big an issue as a remove. –  Karl Bielefeldt Mar 3 '12 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? –  glenviewjeff Mar 3 '12 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 '12 at 22:25
    
If you're interested, see my edit. I implemented and packaged an extension to ArrayList to accomplish this. –  glenviewjeff Mar 3 '12 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 '12 at 23:27
show 3 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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