Source: CS61B — ArraySet lecture example (Iterable/Iterator design)

1. The Problem: How Does for (T x : obj) Actually Work?

Java's for-each loop looks like magic, but it's just syntactic sugar. The compiler needs some guaranteed protocol that any class can implement so that for (T x : obj) works on it — whether obj is an ArrayList, a HashSet, or a custom ArraySet.

That guaranteed protocol is split into two separate interfaces, each with a distinct job.

2. Iterable<T> — A Promise, Not a Mechanism

public interface Iterable<T> {
    Iterator<T> iterator();
}

Iterable has exactly one method. Implementing it means: "objects of this class can be looped over." It does not do any of the actual walking-through-elements work itself — it only promises to produce something (an Iterator) that can.

ArraySet<T> implements Iterable<T> → ArraySet is declaring it can be used in a for-each loop, and as proof, it must supply a working iterator() method.

3. Iterator<T> — The Protocol for Walking Through Elements

public interface Iterator<T> {
    boolean hasNext();
    T next();
}

This is the interface that actually defines "how to walk." It requires two things: can you tell me if there's a next element, and can you give me the next element (advancing your internal pointer as you do so).

Key design insight: Iterable and Iterator are deliberately two different objects, not one. The collection (ArraySet) does not itself track "how far along the traversal we are" — that job belongs to a separate, freshly-created Iterator object. This separation is what allows two independent for-each loops over the same ArraySet to run at once without interfering (e.g. a nested loop iterating the same set twice) — each call to .iterator() hands out a brand-new object with its own independent position counter.

4. ArraySetIterator — The Concrete Implementation, as an Inner Class

private class ArraySetIterator implements Iterator<T> {
    private int wizPos;
    public ArraySetIterator() {
        wizPos = 0;
    }
    public boolean hasNext() {
        return wizPos < size;
    }
    public T next() {
        T returnItem = items[wizPos];
        wizPos += 1;
        return returnItem;
    }
}

This is where Iterator<T> actually gets implemented for ArraySet. Two things matter here:

5. Tracing Through a For-Each Loop

for (int i : aset) {
    System.out.println(i);
}

The compiler expands this into: