EMZETT.
Login

Iterator

In short: An object that goes through a collection element by element, without needing to know its internal structure — the basis for the for-each loop.

In more detail: The central methods are hasNext() (is there another element?) and next() (returns it and advances). Unlike a direct for loop over an index, an Iterator allows safely removing elements DURING iteration via remove(), without triggering a ConcurrentModificationException.

In Depth

List<String> names = new ArrayList<>(List.of("Anna", "Ben", "Clara", "Ben"));
 
Iterator<String> it = names.iterator();
while (it.hasNext()) {
    String name = it.next();
    if (name.equals("Ben")) {
        it.remove(); // safe removal DURING iteration
    }
}
System.out.println(names); // [Anna, Clara]
 
// This throws a ConcurrentModificationException:
for (String name : names) {
    if (name.equals("Anna")) {
        names.remove(name); // direct removal in a for-each loop - FORBIDDEN
    }
}

A for-each loop (for (String name : names)) is actually just syntactic sugar that, under the hood, creates exactly one Iterator with hasNext()/next() — that’s why for-each only works at all with types that implement the Iterable interface. If you call list.remove(element) DIRECTLY inside such a loop (instead of via the iterator itself), the internally created iterator notices the structural change and throws a ConcurrentModificationException on the next next() call, to prevent the iteration from ending up in an inconsistent state. The explicit route via Iterator.remove() is the only safe way to remove elements during an iteration.

Implementing your own Iterable

Any custom class can be made iterable itself by implementing Iterable<T> and providing an iterator() method that returns a suitable Iterator — this is exactly the mechanism through which for-each also works with hand-written data structures, not just the standard collections:

class NumberRange implements Iterable<Integer> {
    private final int from, to;
    NumberRange(int from, int to) { this.from = from; this.to = to; }
 
    public Iterator<Integer> iterator() {
        return new Iterator<>() {
            int current = from;
            public boolean hasNext() { return current <= to; }
            public Integer next() { return current++; }
        };
    }
}
 
for (int n : new NumberRange(1, 5)) {
    System.out.println(n); // 1 2 3 4 5
}

ListIterator — a bidirectional extension

For List implementations, there’s additionally ListIterator, which extends the normal Iterator with backward navigation (hasPrevious()/previous()), replacing the current element (set()), and inserting at the current position (add()) — useful when, during iteration, you need not just removal but also modification or insertion.

See also: For Loop, Collections, List