How would you make your own class iterable so it works with for-each, and what contract must your Iterator honor?
answer
- implement Iterable<T>.iterator() → fresh Iterator<T>
- Private inner class holds per-iterator state
- next() throws NoSuchElementException when empty
- hasNext() pure, no side effects, no advance
- Mutable → consider fail-fast modCount
basics
~10 sImplement Iterable<T> and return an Iterator<T> from iterator(). The iterator's hasNext() must report whether more elements remain, and next() must return the next one (or throw NoSuchElementException when none). Then for-each just works.
solid answer
~40 sMake the class implement Iterable<T> and supply iterator() that returns a fresh Iterator<T> — usually a private inner class holding the traversal state (an index or node pointer). The Iterator contract: hasNext() returns true iff a subsequent next() would succeed and must not advance; next() returns the next element and advances, throwing NoSuchElementException when exhausted; remove() is optional and should throw UnsupportedOperationException if unsupported (its default already does). Each iterator() call must yield an independent cursor so multiple traversals don't interfere. Keep hasNext() side-effect-free and idempotent. Decide whether the iterator is fail-fast (track a modCount and throw ConcurrentModificationException on external structural change) — recommended for mutable collections to catch bugs. For lazy/infinite sources, hasNext() can compute on demand. Once Iterable is implemented, for-each, forEach(Consumer), and any Iterable-accepting API work automatically.
code
java · 18 linespublic final class Pair<T> implements Iterable<T> {
private final T a, b;
public Pair(T a, T b) { this.a = a; this.b = b; }
@Override public Iterator<T> iterator() {
return new Iterator<>() {
private int i = 0; // independent state
@Override public boolean hasNext() { return i < 2; }
@Override public T next() {
if (!hasNext()) throw new NoSuchElementException();
return (i++ == 0) ? a : b;
}
};
}
}
// now usable in for-each:
for (String s : new Pair<>("x", "y")) System.out.println(s);go deeper
Knows implementing Iterable with an iterator() method enables for-each, and that next()/hasNext() must be provided.
Implements a correct iterator with per-call fresh state and proper NoSuchElementException, and avoids side effects in hasNext().
Designs the inner-class cursor, chooses a consistency model (fail-fast vs snapshot), supports optional remove() correctly, and exploits lazy/on-demand evaluation.
Reasons about the Iterable abstraction as an API boundary — independence guarantees, laziness/infinite sources, concurrency model, and how it composes with streams and Iterable-accepting libraries.
## Goal You have a custom class that conceptually holds a sequence — say a fixed-size `Ring<T>` buffer or a `Range`. To let clients write `for (T x : myThing)` and to plug into any API that takes an `Iterable`, you implement the `Iterable<T>` contract. ## Step 1: implement Iterable<T> `Iterable<T>` requires one method: ```java public class Range implements Iterable<Integer> { private final int from, toExclusive; Range(int from, int toExclusive) { this.from = from; this.toExclusive = toExclusive; } @Override public Iterator<Integer> iterator() { return new RangeIterator(); } private final class RangeIterator implements Iterator<Integer> { private int cursor = from; // independent per-iterator state @Override public boolean hasNext() { return cursor < toExclusive; } @Override public Integer next() { if (!hasNext()) throw new NoSuchElementException(); return cursor++; } } } ``` Key design choices visible here: - **Private inner class for the cursor.** It is an *inner* (non-static) class so it can read the outer instance's fields (`from`, `toExclusive`). Each `iterator()` call `new`s a fresh one, giving every traversal its own `cursor`. - **State lives on the iterator, not the collection.** That independence is what lets nested loops over the same object work. ## Step 2: honour the Iterator contract precisely 1. **`hasNext()` must be pure and repeatable.** Calling it twice in a row must return the same answer and must **not** advance the cursor or consume input. A common bug is doing I/O or mutation inside `hasNext()`. 2. **`next()` returns the next element and advances.** When nothing remains it must throw `java.util.NoSuchElementException` — not return null, not throw something else. The for-each desugaring relies on `hasNext()` guarding `next()`, but defensive `next()` should still throw when misused. 3. **`remove()` is optional.** Since Java 8 it is a `default` that throws `UnsupportedOperationException`, so an immutable/read-only iterator can simply not override it. If you do support removal, it must remove the element last returned by `next()` and is illegal before the first `next()` or after a previous `remove()`. 4. **`forEachRemaining()`** has a sensible default (loop on hasNext/next); override only for efficiency. ## Step 3: decide your consistency model For an **immutable** structure, nothing can change underneath the iterator, so no extra work is needed. For a **mutable** collection you must pick: - **Fail-fast** (recommended for general-purpose mutable collections): keep an `int modCount` on the collection, increment it on every structural change, snapshot it in the iterator as `expectedModCount`, and in `next()` throw `ConcurrentModificationException` if they diverge. This mirrors `java.util` and catches 'modified during iteration' bugs early. - **Snapshot** (copy the data at iterator-creation; never throws, but iterates a stale view) — appropriate for concurrent read-mostly use. - **Weakly consistent** (traverse live without locking, tolerate concurrent change) — what `ConcurrentHashMap` does; harder to get right. ## Step 4: free wins once Iterable is implemented Implementing `Iterable` immediately gives you: - the enhanced **for-each** loop; - the **`forEach(Consumer)`** default method on `Iterable`; - usability with any library/method whose parameter type is `Iterable<? extends T>` (e.g. `List.copyOf`, JUnit assertions, etc.). ## Lazy and infinite sources Because `hasNext()`/`next()` are pulled on demand, an `Iterable` need not hold all elements in memory. A line-reader iterator can fetch the next line lazily; an infinite generator can always return `hasNext() == true`. This is the same pull-based model that underlies many streaming abstractions. ## Common pitfalls - Returning the *same* iterator instance from every `iterator()` call (breaks concurrent/nested traversal and re-iteration). - Side effects in `hasNext()`. - Returning `null` from `next()` instead of throwing `NoSuchElementException` on exhaustion. - Making the cursor a `static` nested class when it needs outer-instance state, or capturing mutable outer state without a fail-fast guard.
- Why return a new iterator from each iterator() call instead of caching one?Independent cursors let multiple/nested for-each loops over the same object run without clobbering each other's position, and allow re-iteration. A shared, stateful iterator would be exhausted after one pass and corrupt concurrent traversals.
- Must a custom iterator be fail-fast?No — it is a design choice. Immutable sources need nothing; for mutable ones, fail-fast (modCount) is recommended to catch concurrent-modification bugs, but snapshot or weakly-consistent models are valid alternatives depending on requirements.
saying these in an interview costs you the question
- Returning the same cached iterator from every iterator() call
- Putting side effects or advancing logic inside hasNext()
- Returning null from next() on exhaustion instead of throwing NoSuchElementException
- Making the cursor static when it needs the outer instance's data
- Claiming you must implement Iterator on the class itself — you return one from iterator()