Java 46: Iterators, Iterable & Fail-Fast vs Fail-Safe
easy⏱ 5 mincoursejava
Iterable & Iterator
Iterable<T> declares one method, Iterator<T> iterator(). Iterator<T> has hasNext(), next(), and a default remove(). The compiler turns for (T x : c) into a while (it.hasNext()) { T x = it.next(); ... }. Implement Iterable and your type works in for-each, streams (StreamSupport), and varargs spreads for free.
for (String s : list) { ... }
// compiles to:
Iterator<String> it = list.iterator();
while (it.hasNext()) { String s = it.next(); ... }
Fail-fast & ConcurrentModificationException
Most java.util collections (ArrayList, HashMap) are fail-fast: they keep a modCount; the iterator snapshots it and throws ConcurrentModificationException on next() if the collection was structurally modified during iteration (even from the same thread!). It's a best-effort bug detector, not a thread-safety guarantee. The fix: remove via iterator.remove(), or use removeIf.
for (String s : list) {
if (s.isBlank()) list.remove(s); // throws CME!
}
list.removeIf(String::isBlank); // correct
// or: Iterator it = list.iterator(); while(...) { it.remove(); }
Fail-safe iterators
Concurrent collections are fail-safe: CopyOnWriteArrayList iterates over a snapshot taken at iterator creation, so writes never throw — but the iterator won't see later writes. ConcurrentHashMap's iterator is weakly consistent: it tolerates concurrent writes and may or may not reflect them. Fail-safe means 'never throws CME', not 'sees a perfectly current view'.
Build fail-fast vs fail-safe iterators
Make a FastList that tracks modCount; its iterator captures expectedModCount and throws 'ConcurrentModificationException' on next() if they diverge. Make a SafeList whose iterator copies the backing array up-front. Iterate both while adding an element mid-loop: the fast one throws, the safe one finishes over the original snapshot. Also implement a custom Range Iterable and sum it with for-each.
removeIf over manual iteration
collection.removeIf(predicate) is the cleanest, fastest way to delete matching elements — it uses the iterator internally and avoids CME. Reach for it before hand-rolling an Iterator.remove() loop; it's also overridable by collections (ArrayList does a single compacting pass).
Quiz: is CME thread-safety?
Does fail-fast iteration make a collection thread-safe? No. modCount checks are best-effort and racy — concurrent modification might be missed or might throw nondeterministically. CME is a debugging aid for single-thread misuse, not a concurrency control. For real concurrency use ConcurrentHashMap/CopyOnWriteArrayList or external synchronization.