Collections

72. Iterator and ConcurrentModificationException

Iterator allows safe traversal and removal; ListIterator adds bidirectional traversal; modifying a collection while iterating via for-each throws ConcurrentModificationException โ€” use iterator.remove() or removeIf() instead.

Java 21 (core language)

Explanation

Java's fail-fast iterators (for ArrayList, HashMap, etc.) maintain a modCount counter that increments on every structural modification. The iterator checks modCount on each next() call; if it doesn't match the value captured at iterator creation, ConcurrentModificationException is thrown. This is a best-effort safety check, not guaranteed under concurrent access.

Safe removal during iteration: use Iterator.remove() โ€” it removes the most recently returned element and updates modCount. The enhanced for-each loop provides no access to the iterator, so you cannot call remove(). Use iterator.remove() via an explicit Iterator, or Collection.removeIf(predicate) (Java 8+) for bulk removal.

ListIterator<E> (for List implementations) adds: hasPrevious(), previous(), add(e) (insert at cursor), set(e) (replace last returned), nextIndex(), previousIndex().

Example

import java.util.*;

public class IteratorDemo {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));

        // ConcurrentModificationException trap
        try {
            for (Integer n : nums) {
                if (n % 2 == 0) nums.remove(n); // WRONG: CME!
            }
        } catch (ConcurrentModificationException e) {
            System.out.println("CME thrown โ€” cannot remove via for-each");
        }

        // CORRECT: Iterator.remove()
        nums = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));
        Iterator<Integer> it = nums.iterator();
        while (it.hasNext()) {
            if (it.next() % 2 == 0) it.remove(); // safe!
        }
        System.out.println("Odds only: " + nums); // [1, 3, 5]

        // CORRECT (cleaner): removeIf
        nums = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));
        nums.removeIf(n -> n % 2 == 0);
        System.out.println("removeIf odds: " + nums); // [1, 3, 5]

        // ListIterator: bidirectional, add, set
        List<String> words = new ArrayList<>(List.of("a", "b", "c"));
        ListIterator<String> li = words.listIterator();
        while (li.hasNext()) {
            String w = li.next();
            li.set(w.toUpperCase()); // replace in-place
        }
        System.out.println("Uppercased: " + words); // [A, B, C]

        // Backward traversal
        while (li.hasPrevious()) {
            System.out.print(li.previous() + " ");
        }
        System.out.println(); // C B A
    }
}

Sources