Introduction

ConcurrentModificationException is thrown when a collection is structurally modified while being iterated, except through the iterator's own remove or add methods. This is a fail-fast behavior designed to detect bugs where code modifies a collection during traversal.

This is one of the most common collection-related errors in Java, especially when filtering or cleaning up elements during a loop.

Symptoms

  • Application throws "java.util.ConcurrentModificationException" during foreach loop
  • Exception occurs at the next iteration after removing an element
  • Code works for some inputs but fails when the removal condition is triggered

Common Causes

  • Using foreach loop and calling list.remove() inside the loop body
  • Modifying a collection from another thread while iterating
  • Using stream().forEach() and modifying the source collection inside the lambda

Step-by-Step Fix

  1. 1.Use Iterator.remove() for safe removal during iteration: The iterator's own remove method is safe.
  2. 2.```java
  3. 3.List<String> items = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));

Iterator<String> it = items.iterator(); while (it.hasNext()) { String item = it.next(); if (item.equals("b")) { it.remove(); // Safe - uses iterator's remove } } // Result: [a, c, d] ```

  1. 1.Use removeIf for predicate-based filtering: Clean one-liner for conditional removal.
  2. 2.```java
  3. 3.List<String> items = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));

// Remove all items matching a condition items.removeIf(item -> item.equals("b")); // Result: [a, c, d] ```

  1. 1.Collect to a new list instead of modifying in place: Create a filtered copy.
  2. 2.```java
  3. 3.List<String> items = Arrays.asList("a", "b", "c", "d");

// Create a new list without the unwanted elements List<String> filtered = items.stream() .filter(item -> !item.equals("b")) .collect(Collectors.toList()); ```

  1. 1.Use concurrent collections for multi-threaded access: CopyOnWriteArrayList for thread-safe iteration.
  2. 2.```java
  3. 3.import java.util.concurrent.CopyOnWriteArrayList;

List<String> items = new CopyOnWriteArrayList<>(Arrays.asList("a", "b", "c", "d"));

// Safe to modify during iteration in multi-threaded context for (String item : items) { if (item.equals("b")) { items.remove(item); // Safe with CopyOnWriteArrayList } } ```

Prevention

  • Never call list.remove() inside a foreach loop -- use Iterator.remove() or removeIf()
  • Use removeIf() for simple predicate-based filtering
  • Use CopyOnWriteArrayList or ConcurrentHashMap for concurrent read-write scenarios
  • Prefer immutable collections and functional filtering over in-place modification