<code>Iterator</code> and <code>removeIf</code> in Java

Iterator is the interface every Java collection exposes to walk through its elements one at a time. Three methods: hasNext(), next(), remove(). The enhanced for loop is syntactic sugar over it.

The basic contract

var it = list.iterator();
while (it.hasNext()) {
    String s = it.next();
    if (s.isEmpty()) it.remove();          // βœ… safe removal
}

remove() removes the element last returned by next(). Calling it before next() or twice in a row throws IllegalStateException.

The enhanced for under the hood

for (String s : list) send(s);

// Is equivalent to:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String s = it.next();
    send(s);
}

removeIf β€” the modern idiom (Java 8+)

list.removeIf(String::isEmpty);
list.removeIf(user -> user.age() < 18);
map.entrySet().removeIf(e -> e.getValue() == null);

Cleaner than an explicit iterator loop, and the implementation batches the work for better performance on large collections.

Why you can't remove during a for-each

for (String s : list) {
    if (s.isEmpty()) list.remove(s);        // ❌ ConcurrentModificationException
}

The iterator tracks a modification count. Changing the collection without going through the iterator (or not using the iterator at all) desyncs that count and triggers the exception.

ListIterator β€” walk forward and back

var it = list.listIterator();
while (it.hasNext()) {
    int i = it.nextIndex();
    String s = it.next();
    it.set(s.toUpperCase());                // replace in-place
}
// Can also .previous(), .hasPrevious(), .add() while iterating

Fail-fast vs fail-safe

  • Fail-fast (ArrayList, HashMap): detect concurrent modification and throw.
  • Fail-safe (CopyOnWriteArrayList, ConcurrentHashMap): iterate over a snapshot β€” no exception, but you may miss concurrent changes.

Common mistakes

  • Modifying during for-each β€” use removeIf or an explicit iterator.
  • Calling next() without hasNext() β€” NoSuchElementException.
  • Using an iterator after the source collection is gone out of scope β€” undefined behaviour.

Related

Pillar: Java collections. Siblings: ConcurrentModificationException, for-each.