Java
ArrayList
Iteration
ConcurrentModificationException
Error Handling

How to avoid ConcurrentModificationException while removing elements from `ArrayList` while iterating it?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

ConcurrentModificationException usually appears when Java code modifies a collection structurally while iterating over it with a fail-fast iterator. When the goal is to remove elements from an ArrayList during iteration, the safe pattern is to remove through the iterator itself or to restructure the operation so the list is not modified mid-loop in an unsafe way.

Why the Exception Happens

A for-each loop uses an iterator under the hood. If you remove elements from the list directly while that iterator is active, Java detects the structural change and throws ConcurrentModificationException.

java
1List<String> values = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
2
3for (String item : values) {
4    if (item.equals("c")) {
5        values.remove(item);
6    }
7}

That fails because the list is modified outside the iterator that is performing the traversal.

Safe Option 1: Use an Explicit Iterator

The standard safe solution is to use an explicit iterator and call remove() on that iterator.

java
1import java.util.ArrayList;
2import java.util.Arrays;
3import java.util.Iterator;
4import java.util.List;
5
6List<String> values = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
7Iterator<String> it = values.iterator();
8
9while (it.hasNext()) {
10    String item = it.next();
11    if (item.equals("c")) {
12        it.remove();
13    }
14}
15
16System.out.println(values);

This works because the iterator updates its own internal modification state correctly.

Safe Option 2: Use removeIf

If the goal is simply to remove every element matching a predicate, modern Java gives you a cleaner option.

java
1import java.util.ArrayList;
2import java.util.Arrays;
3import java.util.List;
4
5List<String> values = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
6values.removeIf(item -> item.equals("c"));
7System.out.println(values);

For many cases, removeIf is the most readable answer.

Safe Option 3: Collect Then Remove

Another pattern is to collect the elements to remove first and then remove them afterward.

java
1import java.util.ArrayList;
2import java.util.Arrays;
3import java.util.List;
4import java.util.stream.Collectors;
5
6List<String> values = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
7List<String> toRemove = values.stream()
8    .filter(item -> item.equals("c"))
9    .collect(Collectors.toList());
10
11values.removeAll(toRemove);
12System.out.println(values);

This can be useful when the removal rule is complex or when you want to inspect the removed elements separately.

What About CopyOnWriteArrayList?

CopyOnWriteArrayList avoids this exception because iteration happens over a snapshot, not over a mutable live view. But it is not a drop-in answer for ordinary ArrayList logic. It has different performance tradeoffs and is mainly useful for read-heavy concurrent scenarios.

If the code is single-threaded and simply wants safe removal while iterating, a normal iterator or removeIf is usually better.

Choose the Simplest Safe Pattern

As a practical rule:

  • use iterator.remove() when you are already iterating manually,
  • use removeIf when the logic is just predicate-based removal,
  • use collect-then-remove when the removal rule or bookkeeping needs more structure.

That keeps the intent of the code visible instead of turning collection mutation into a side effect hidden inside a loop.

Common Pitfalls

A common mistake is assuming the exception means several threads are involved. It often happens in single-threaded code too, because the issue is iterator safety, not necessarily real concurrency.

Another issue is removing directly from the list inside a for-each loop. That is the classic fail-fast pattern.

Developers also sometimes reach for CopyOnWriteArrayList too quickly when the real need is simply to use the iterator's own remove method.

Summary

  • 'ConcurrentModificationException usually means a fail-fast iterator saw an unsafe structural change.'
  • Use iterator.remove() when removing during manual iteration.
  • Use removeIf when the goal is predicate-based removal.
  • Collect elements first and remove later if the logic needs extra structure.
  • Do not modify an ArrayList directly from inside a for-each loop.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

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

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions