SwadhyAI Notes

All Java notes

Java Iterator

›Short versionOpen if you only have a minute.
  • An iterator walks a collection with hasNext and next. remove deletes the element just returned.
  • Everyday collections are fail-fast. A structural change outside the iterator throws ConcurrentModificationException.
  • The check compares modification counts. It finds single-threaded bugs. It is not a lock.
  • The enhanced for loop uses an iterator. list.remove inside that loop is the usual crash.
  • iterator.remove after next is safe. removeIf is the safe bulk delete. ListIterator can also add and move backward.
  • Concurrent collections are weakly consistent instead of fail-fast. Do not expect ConcurrentModificationException there.

An is the cursor behind every for-each loop over a collection. Most of the time you never see it. You see it when you need to delete the current element, or when a iterator throws because the collection moved.

The throw is ConcurrentModificationException. The name sounds like threads. The usual cause is one thread, one loop, and a remove on the list itself.

What the iterator is counting

The collection keeps a . Creating an iterator snapshots it. next checks it. is special because it increments the collection and then refreshes the snapshot, so the following next still matches.

set on an ArrayList replaces a slot and is not a structural change, so it does not trip the iterator. add, remove, and clear do. Sorting a list does too: the order change is structural, and an iterator opened beforehand fails on its next step.

A is the cursor that can step back and insert. On a LinkedList it is also the only way the “constant-time splice” story is true, because the cursor already sits on the node. A iterator is the other family, used by the concurrent collections, and it will not throw just because another thread put a key.

Delete through the cursor

IteratorDemo.java
List<String> names = new ArrayList<>(List.of("Ada", "Grace", "Lin"));

Iterator<String> it = names.iterator();
while (it.hasNext()) {
    if (it.next().equals("Grace")) {
        it.remove(); // legal once per next()
    }
}

names.removeIf(name -> name.equals("Lin")); // bulk, and consistent

// names.remove(...) inside a for-each loop is the fail-fast crash

A for-each loop over an ArrayList calls names.remove(0) on the first element. When does ConcurrentModificationException throw, and what call should replace it?

The for-each loop’s hidden iterator notices the mismatch on the next call to next, often on the following element rather than on the remove line itself. Use iterator.remove after next, or names.removeIf, which walks and deletes without leaving a stale cursor.