Reversing the logic a little bit on iterators can often make a big difference in the way the code reads, and it can remove code duplication.
One of the performance issues of iterators is that each time you call next(), you call hasNext() twice... consider a typical iterator use case:
while (it.hasNext()) {
Object o = it.next();
... do something with o.
}
Now, you call hasNext() in the loop, and, internally, the first thing next() does, is call hasNext() again.
If the hasNext() method is 'heavy', it can be quite expensive. This is especially true because, often, most of the same work is required yet again, to perform the next() (a third time!).
There is a trick to prevent this work duplication: Do the work once in advance, and remember the state.
public class IteratorOfIterator implements Iterator<Integer>{
private final Iterator<Iterator<Integer>> iteratorOfIterator;
private Iterator<Integer> currentIterator = null;
private Integer next = null;
private boolean isvalid = false;
public IteratorOfIterator(Iterator<Iterator<Integer>> iterator) {
this.iteratorOfIterator = iterator;
// call advance from the constructor!!
advance();
}
private void advance() {
if (currentIterator != null && currentIterator.hasNext()) {
isvalid = true;
next = currentIterator.next();
return;
}
currentIterator = null;
while (currentIterator == null && iteratorOfIterator.hasNext()) {
currentIterator = iteratorOfIterator.next();
if (currentIterator != null && currentIterator.hasNext()) {
next = currentIterator.next();
isvalid = true;
return;
}
}
next = null;
isvalid = false;
}
@Override
public boolean hasNext() {
return isvalid;
}
@Override
public Integer next() {
if (isvalid) {
throw new NoSuchElementException("the stuff cannot be null.");
}
Integer val = next;
advance();
return val;
}
@Override
public void remove() {
throw new UnsupportedOperationException("The remove operation is not supported.");
}
}
The above code:
- reduces the multiple hasNext() calls to a simple boolean check
- the advance method is called only once per item
- it handles null values in both the iteratorOfIterators and in the currentIterator