Explain Codes LogoExplain Codes Logo

Iterating through a Collection, Avoiding ConcurrentModificationException When Removing Objects in a Loop

java
concurrentmodificationexception
iterator
removeif
Nikita BarsukovbyNikita Barsukov·Nov 1, 2024
TLDR

Best practice to avoid ConcurrentModificationException during iteration is to utilize an Iterator's remove() built-in method. This secure operation permits an element deletion from the collection without any exception.

for (Iterator<YourType> it = yourCollection.iterator(); it.hasNext();) { YourType item = it.next(); if (shouldRemove(item)) { it.remove(); // One small step for you, one giant leap for avoiding exceptions! } }

Core problem: Concurrent modifications

The crux of this problem lies in modifying a collection while iterating over it. Deftly named, ConcurrentModificationException gets triggered when Java notices such interference during iteration.

Enter stage: The Iterator's remove() method

The Iterator interface pacifies this predicament with its remove() method. This safeguard maintains a consistent internal count (expectedModCount), making alterations in the collection ConcurrentModificationException-proof.

Choosing removal tools wisely

Venturing to modify a collection during iteration? Forget about the enhanced for-loop or the stream API. Instead, reach for:

  • Iterator's remove(): for hands-on control
  • Collection's removeIf(Predicate): for a streamlined condition-based removal

Using removeIf not only promises safety from exceptions but also ensures clear and readable code with its single-line filtering capability.

Clever removal using Predicates

With an expansive array of tools, Java doesn’t fall short of efficient solutions. The Collection.removeIf(Predicate) leads to a much cleaner and safe approach for removal operations. This modern method deters any risk of ConcurrentModificationException.

collection.removeIf(i -> someCondition(i)); // Magic tool, isn't it?

Extra Care: Maps

Venturing outside the collections and into the world of Map? Keep those same guard rails up. Maps don’t support the removeIf method directly, but Iterator can still have your back.

Iterator<Map.Entry<KeyType, ValueType>> it = map.entrySet().iterator(); while (it.hasNext()) { if (shouldRemove(it.next().getKey(), it.next().getValue())) { it.remove(); // Maps. Not the territory, but we still conquer! } }

Also, one can exploit Map.forEach alongside entrySet().removeIf for a cleaner deletion operation in a map.

map.entrySet().removeIf(entry -> shouldRemove(entry));