liveBook · Manning

Iterator contract

As explained in 100 Java Mistakes and How to Avoid Them

The iterator contract is the behavioral specification governing how an Iterator reports availability, returns elements, and signals exhaustion.

An iterator must report availability without consuming or advancing an element, return the next element from next(), and signal exhaustion with NoSuchElementException. A loop may hide violations because enhanced for uses only one access pattern. section 8.13 section 8.14

The loop that hides the defect

An iterator whose hasNext() increments its cursor and whose next() merely returns the cursor can produce the expected values in an enhanced for loop. The same iterator fails when Collections.min() calls next() before hasNext(), and it does not correctly throw NoSuchElementException at exhaustion. section 8.13

Implement custom iterators defensively:

  • Keep availability checks observational: repeated hasNext() calls must not consume or skip elements. section 8.13
  • Make next() work when called directly, returning the next element or throwing NoSuchElementException when none remains. section 8.13
  • When determining availability requires reading ahead, cache the value, reuse it across hasNext() calls, and clear it only after next() returns it. section 8.13
  • Prefer existing iterator-producing APIs such as IntStream.range(0, max).iterator() or reader.lines().iterator() when they fit. section 8.13
return new Iterator<>() {
  String next;

  public boolean hasNext() {
    if (next != null) return true;
    try {
      next = reader.readLine();
    } catch (IOException e) {
      throw new UncheckedIOException(e);
    }
    return next != null;
  }

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

Shows a corrected BufferedReader adapter that caches one line, tolerates repeated hasNext() calls, supports direct next(), and throws on exhaustion. section 8.13

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Demonstrates broken and corrected implementations, including cached look-ahead, but does not discuss iterator internals beyond state management.
Examples
Uses a range iterator, Collections.min(range(10)), a BufferedReader line adapter, IntStream.range(), and reader.lines().
What it assumes
Assumes familiarity with Java collections, iterators, enhanced for loops, and exceptions while teaching contract-sensitive call patterns.
What you can do after
Build custom iterators that tolerate valid call sequences and signal exhaustion consistently.
How it connects
Connects iterators with enhanced for loops, Collections.min(), BufferedReader, IntStream, and streams.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Java Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.