Why is this an issue?

Calling Iterator.hasNext() is not supposed to have any side effects and hence should not change the iterator’s state. Iterator.next() advances the iterator by one item. So calling it inside Iterator.hasNext() breaks the hasNext() contract and will lead to unexpected behavior in production.

How to fix it

How to fix this issue strongly depends on the specific implementation of the iterator. Make sure that the logic of the hasNext() implementation does not change the state of the iterator or any underlying data sources. Instead, it should merely return state information.

Code examples

Noncompliant code example

class MyIterator implements Iterator<Integer> {

  private Queue<Integer> elements;

    ...

  @Override
  public boolean hasNext() {
    try {
      next(); // Noncompliant, next() is called from hasNext()
      return true;
    } catch (NoSuchElementException e) {
      return false;
    }
  }

  @Override
  public Integer next() {
    return elements.remove();
  }
}

Compliant solution

class MyIterator implements Iterator<Integer> {

  private Queue<Integer> elements;

    ...

  @Override
  public boolean hasNext() {
    return !elements.isEmpty(); // Compliant, no call to next()
  }

  @Override
  public Integer next() {
    return elements.remove();
  }
}

Resources