Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Iterator implementation - next() and hasNext() enforcing order

I have an implementation of java.util.Iterator which requires that the call to next() should always be proceeded by a call to hasNext(). (This is because results are returned asynchronosly in a multi threaded environment and it is never clear how many more results there might be).

Would it be 'correct' to properly document this in the JavaDoc and then throw a RuntimeException if this was violated. Or is this stretching the Iterator interface a little too far?

All thoughts appreciated?

like image 227
Dan Avatar asked Feb 01 '10 11:02

Dan


5 Answers

I might be missing something here, but why not call hasNext() internally in your implementation?

like image 141
Fabian Steeg Avatar answered Nov 01 '22 11:11

Fabian Steeg


Requiring that hasNext() be called before next() violates the iterator contract. You really should rewrite it so that next() simply throws a NoSuchElementException if there is no element to return.

like image 38
uckelman Avatar answered Nov 01 '22 11:11

uckelman


I imagine you're doing something like this:

class IteratorImpl<T> implements Iterator<T> {
  private Source<T> source = ...
  private T next = null;

  public boolean hasNext() {
    if(next == null) {
      next = source.poll();
    }
    return next != null;
  }

That sounds OK to me. I can't imagine a situation where you'd want to use next without hasNext - it would be a recipe for exceptions.


EDIT:

The doc for hasNext() says:

Returns true if the iteration has more elements. (In other words, returns true if next would return an element rather than throwing an exception.)

To me, the implementation does not violate the contract. However, I would (as Fabian Steeg implies) still implement next() as:

  public T next() {
    if(!hasNext()) {
      throw new NoSuchElementException();
    }
    T ret = next;
    next = null;
    return ret;
  }

I mean, what does that check really cost you?

You must check and throw a NoSuchElementException as per the API contract. Either testing on !hasNext() or next == null will meet this criteria, I believe, but I would favour the former.

If someone is catching NoSuchElementException instead of calling hasNext(), you probably have bigger problems.

like image 36
McDowell Avatar answered Nov 01 '22 11:11

McDowell


If your hasNext() and next() calls aren't in a synchronized block/method, it is not guaranteed that you will have elements even if you call hasNext() before next().

The contract of the Iterator interface is that NoSuchElementException should be thrown if there are no more elements. So proceed with the next() method until such an exception arises.

That said, take a look at the java.util.concurrent package - it has concurrent collections whose iterators may help you - i.e. you can use these collections and iterators instead of implementing your own.

like image 20
Bozho Avatar answered Nov 01 '22 13:11

Bozho


I would rather throw an exception from next(), when there are no more elements. In a multi-threaded environment hasNext() is pretty useless anyway.

like image 2
Joonas Pulakka Avatar answered Nov 01 '22 12:11

Joonas Pulakka