library
intermediateIterator, ListIterator & Spliterator
Understand the three iteration interfaces, their capabilities, and when Spliterator enables parallel processing.
Three interfaces for walking a collection, with increasing capability.
Iterator = a bookmark in a book (forward only). ListIterator = a bookmark you can move both ways. Spliterator = tearing the book in half so two people can read simultaneously.
Key Concepts
1
Iterator forward only hasNext, next, remove
ListIterator both directions, Lists + previous, set, add, nextIndex
Spliterator splittable, for streams + trySplit, tryAdvance2
Iterator is what the for-each loop uses.
for (String s : list) { ... }Iterator
3
// compiles to roughly
Iterator<String> it = list.iterator();
while (it.hasNext()) { String s = it.next(); ... }4
Which is why for-each works on a Set and a Queue, where an indexed loop has nothing to index.
SetQueue
5
Removing during iteration must go through the iterator.
for (String s : list)
if (s.isEmpty()) list.remove(s); // ConcurrentModificationException6
Iterator<String> it = list.iterator();
while (it.hasNext())
if (it.next().isEmpty()) it.remove(); // correct7
list.removeIf(String::isEmpty); // better8
ListIterator adds backwards movement and replacement:
ListIterator<String> it = list.listIterator();
while (it.hasNext()) {
String s = it.next();
it.set(s.trim()); // replace in place
if (s.isBlank()) it.add("?"); // insert after the cursor
}ListIterator
9
It only exists for List, because the other collections have no position to go back to.
List
10
Spliterator exists so streams can go parallel.
trySplit() hand off half the elements to another thread
tryAdvance(action) process one element
forEachRemaining process the rest
characteristics() SIZED, ORDERED, SORTED, DISTINCT, IMMUTABLESpliterator
11
collection.stream() builds one internally, and parallelStream() calls trySplit repeatedly to divide the
work.
collection.stream()parallelStream()trySplit
12
Characteristics are what make parallelism efficient. An ArrayList reports SIZED and splits exactly in
half in constant time. A LinkedList cannot, so it splits badly and parallel streams over one rarely pay
off. That is the practical consequence of the interface.
ArrayListSIZEDLinkedList
13
Fail-fast is best effort. Iterator throws ConcurrentModificationException when it notices a
structural change, but it is not guaranteed to notice. Never write code that catches it.
IteratorConcurrentModificationException
14
What the interviewer is probing.1. "How do you remove elements while iterating?" Probing: the safe mechanisms. Stalls: "Call
list.remove in the loop." Moves up: removeIf, or iterator.remove — modifying the collection
directly throws ConcurrentModificationException.
15
2. "Why does removing the second-to-last element sometimes not throw?" Probing: the hasNext
check, which makes the bug look intermittent. Stalls: "It always throws." Moves up: after the
removal hasNext compares the cursor against the new smaller size, returns false, and the loop exits
before any check runs.
16
3. "What does Spliterator add over Iterator?" Probing: parallelism. Stalls: "Nothing much."
Moves up: trySplit, so a stream can divide the work across threads, plus characteristics like
SIZED and ORDERED that decide how efficiently it splits.
17
4. "Why do parallel streams work poorly over a LinkedList?" Probing: the link between
structure and splitting. Stalls: "They work the same." Moves up: it cannot report a size or
split in constant time, so the work divides badly — an ArrayList halves exactly.