Java
Programming
Collection Handling
ConcurrentModificationException
Loop Optimization

Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

ConcurrentModificationException is one of the most common surprises in Java collection code. It usually appears when you iterate over a collection and then change that same collection through some path other than the iterator that is currently walking it. The fix is not complicated, but it depends on how you want to remove elements and what kind of collection logic you need.

Why the Exception Happens

Most standard Java collection iterators are fail-fast. They track whether the collection’s structure changed unexpectedly while iteration was in progress.

This code throws the exception:

java
1List<String> names = new ArrayList<>(List.of("Ann", "Bob", "Cara"));
2
3for (String name : names) {
4    if (name.startsWith("B")) {
5        names.remove(name);
6    }
7}

The problem is not that removal is forbidden. The problem is that the for-each loop is using an iterator behind the scenes, while names.remove(name) mutates the list outside that iterator.

Use the Iterator’s remove() Method

If you need to remove items while walking the collection, use an explicit iterator and call iterator.remove().

java
1import java.util.ArrayList;
2import java.util.Iterator;
3import java.util.List;
4
5public class SafeRemove {
6    public static void main(String[] args) {
7        List<String> names = new ArrayList<>(List.of("Ann", "Bob", "Cara"));
8
9        Iterator<String> it = names.iterator();
10        while (it.hasNext()) {
11            String name = it.next();
12            if (name.startsWith("B")) {
13                it.remove();
14            }
15        }
16
17        System.out.println(names); // [Ann, Cara]
18    }
19}

This is the classic safe solution because the iterator updates the collection in the way it expects.

Use removeIf() for Predicate-Based Removal

If your goal is simply "remove everything that matches this condition," removeIf() is usually the cleanest option.

java
1List<String> names = new ArrayList<>(List.of("Ann", "Bob", "Cara"));
2names.removeIf(name -> name.startsWith("B"));
3
4System.out.println(names); // [Ann, Cara]

This is concise, readable, and ideal when the logic is just a boolean predicate.

Use ListIterator for More Complex List Edits

If you need to remove, replace, or add while iterating a List, ListIterator gives you more control than a plain Iterator.

java
1import java.util.ArrayList;
2import java.util.List;
3import java.util.ListIterator;
4
5List<String> values = new ArrayList<>(List.of("a", "b", "c"));
6ListIterator<String> it = values.listIterator();
7
8while (it.hasNext()) {
9    String value = it.next();
10    if (value.equals("b")) {
11        it.set("beta");
12    }
13}
14
15System.out.println(values); // [a, beta, c]

If you only need removal, a regular iterator is enough. If you need richer list editing during traversal, ListIterator is the right tool.

Remove Later by Collecting Targets First

Sometimes the removal condition depends on cross-checking several collections or performing side effects. In that situation, collecting the elements to remove and deleting them afterward can be clearer.

java
1List<String> names = new ArrayList<>(List.of("Ann", "Bob", "Cara"));
2List<String> toRemove = new ArrayList<>();
3
4for (String name : names) {
5    if (name.length() == 3) {
6        toRemove.add(name);
7    }
8}
9
10names.removeAll(toRemove);
11System.out.println(names); // []

This uses more memory, but sometimes it makes the code easier to reason about.

Do Not Confuse This with Thread Safety

Despite the name, ConcurrentModificationException does not necessarily mean multiple threads are involved. You can trigger it in single-threaded code.

If multiple threads really are modifying the same collection, you have a different problem: thread safety. In that case, consider concurrent collections such as CopyOnWriteArrayList or proper synchronization. The iterator-removal pattern solves structural modification during iteration, not shared-memory concurrency on its own.

Common Pitfalls

The biggest mistake is removing directly from the collection inside a for-each loop. That is the most common path to this exception.

Another mistake is calling iterator.remove() before next(). The iterator must first advance to an element before it can remove that element legally.

Some developers also replace all loops with streams and then end up writing awkward side-effect-heavy code. If removal is the goal, removeIf() or an explicit iterator is often clearer than a stream pipeline.

Finally, do not assume all collection types behave identically. Map removal, list replacement, and concurrent collection semantics all have their own rules.

Summary

  • 'ConcurrentModificationException usually happens when a collection changes outside the iterator that is traversing it.'
  • Use Iterator.remove() when removing during iteration.
  • Use removeIf() when the removal rule is a simple predicate.
  • Use ListIterator when you need richer list modifications such as replace or add.
  • This exception is about fail-fast iteration, not automatically about multithreading.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.