Question
How to Remove Items While Iterating a Collection in Java Without ConcurrentModificationException
Question
I want to iterate through a Java Collection and remove elements that match a condition. A loop like this is known to cause ConcurrentModificationException:
for (Object item : l) {
if (condition(item)) {
l.remove(item);
}
}
For example:
public static void main(String[] args) {
Collection<Integer> l = new ArrayList<>();
for (int i = 0; i < 10; ++i) {
l.add(4);
l.add(5);
l.add(6);
}
for (int i : l) {
if (i == 5) {
l.remove(i);
}
}
System.out.println(l);
}
This throws:
Exception in thread "main" java.util.ConcurrentModificationException
Why does this happen even though only one thread is involved? What is the best way to remove items from a Collection while looping through it, especially when the collection is arbitrary and not necessarily an ArrayList?
Short Answer
By the end of this page, you will understand why ConcurrentModificationException happens in Java when modifying a collection during iteration, why it is not really about multiple threads, and how to safely remove elements using an Iterator, removeIf, or other appropriate patterns.
Concept
ConcurrentModificationException happens when a collection is structurally modified while it is being iterated in an unsafe way.
In Java, the enhanced for loop:
for (int i : l) {
...
}
is actually using an Iterator behind the scenes. That iterator expects the collection to remain unchanged except through the iterator's own remove() method.
When you call:
l.remove(i);
you modify the collection directly, not through the iterator. The iterator notices that the collection changed unexpectedly and throws ConcurrentModificationException.
Why the name is confusing
Despite its name, this exception does not require multiple threads. Here, "concurrent modification" means:
- one part of your code is iterating
- another operation modifies the collection at the same time
That can happen in a single thread.
Why this matters
If Java allowed arbitrary changes during iteration, the iterator could become inconsistent:
- it might skip elements
- process the same element twice
- read invalid internal state
So Java collections often use . They detect unsafe modification early and throw an exception instead of continuing with unpredictable behavior.
Mental Model
Imagine a collection as a list of names on paper, and an iterator as your finger moving down the page.
If you suddenly tear out a line from the paper while your finger is still tracking positions, your finger may now point to the wrong place. You might skip a name or lose track completely.
Java's iterator says: "If you want to remove the current line, ask me to do it, so I can keep my position correct."
That is exactly what Iterator.remove() does.
Syntax and Examples
Safe removal with Iterator
This is the classic solution that works for an arbitrary Collection:
Collection<Integer> l = new ArrayList<>();
for (int i = 0; i < 10; ++i) {
l.add(4);
l.add(5);
l.add(6);
}
Iterator<Integer> it = l.iterator();
while (it.hasNext()) {
int value = it.next();
if (value == 5) {
it.remove();
}
}
System.out.println(l);
Why this works
it.next()moves to the next elementit.remove()removes the element most recently returned bynext()- the iterator updates its own internal state safely
Modern Java: removeIf
If you are using Java 8 or later, this is often the cleanest option:
Collection<Integer> l = <>();
( ; i < ; ++i) {
l.add();
l.add();
l.add();
}
l.removeIf(value -> value == );
System.out.println(l);
Step by Step Execution
Consider this safe example:
Collection<Integer> l = new ArrayList<>();
l.add(4);
l.add(5);
l.add(6);
Iterator<Integer> it = l.iterator();
while (it.hasNext()) {
int value = it.next();
if (value == 5) {
it.remove();
}
}
Step by step
Initial collection:
[4, 5, 6]
1. Create the iterator
Iterator<Integer> it = l.iterator();
The iterator is now ready to walk through the collection.
2. First loop iteration
int value = it.next();
valuebecomes4- condition
value == 5is false - nothing is removed
Collection remains:
Real World Use Cases
Filtering invalid data
You may want to remove bad values from a collection:
users.removeIf(user -> user.getEmail() == null);
Cleaning cached items
Applications often remove expired entries:
sessions.removeIf(session -> session.isExpired());
Processing API results
After fetching data, you might discard incomplete records:
orders.removeIf(order -> order.getItems().isEmpty());
Validation pipelines
When preparing data for saving, developers remove unusable values:
numbers.removeIf(n -> n < 0);
General collection handling
Because Iterator works with any Collection, it is useful when you do not know the exact implementation type, such as:
ArrayListLinkedListHashSet- other custom collection implementations
Real Codebase Usage
In real projects, developers usually do not write unsafe removal loops. They use one of a few standard patterns.
1. Iterator-based removal
Common when working with a generic Collection or when compatibility matters:
Iterator<Task> it = tasks.iterator();
while (it.hasNext()) {
Task task = it.next();
if (task.isCompleted()) {
it.remove();
}
}
2. removeIf for simple filtering
This is common in modern Java code because it is short and readable:
tasks.removeIf(Task::isCompleted);
3. Build a new filtered collection
Sometimes developers prefer not to mutate the original collection:
List<Task> activeTasks = tasks.stream()
.filter(task -> !task.isCompleted())
.toList();
This is useful when:
- immutability is preferred
- the original collection should remain unchanged
- the code is easier to reason about by creating a result instead of modifying in place
4. Guarding mutation points
In larger codebases, collection updates are often centralized in service methods so mutation is controlled and easier to test.
5. Validation and cleanup passes
A common pattern is to iterate once and remove invalid entries using a clear rule, often before persistence, API output, or batch processing.
Common Mistakes
Mistake 1: Removing from the collection directly inside a for-each loop
Broken code:
for (Integer value : l) {
if (value == 5) {
l.remove(value);
}
}
Why it fails
The loop uses an iterator internally, but the removal happens directly on the collection.
Fix
Use Iterator.remove() or removeIf(...).
Mistake 2: Calling iterator.remove() before next()
Broken code:
Iterator<Integer> it = l.iterator();
it.remove();
Why it fails
remove() can only remove the item most recently returned by next().
Fix
Call next() first:
Iterator<Integer> it = l.iterator();
while (it.hasNext()) {
Integer value = it.next();
(value == ) {
it.remove();
}
}
Comparisons
| Approach | Works on arbitrary Collection | Removes during iteration safely | Readability | Notes |
|---|---|---|---|---|
Enhanced for + collection.remove(...) | Yes | No | High | Usually throws ConcurrentModificationException |
Iterator + iterator.remove() | Yes | Yes | Medium | Classic and reliable solution |
removeIf(...) | Yes | Yes | High | Best for simple predicate-based removal in Java 8+ |
Cheat Sheet
Safe ways to remove while iterating in Java
Use an iterator
Iterator<Type> it = collection.iterator();
while (it.hasNext()) {
Type item = it.next();
if (condition(item)) {
it.remove();
}
}
Use removeIf in Java 8+
collection.removeIf(item -> condition(item));
Avoid this
for (Type item : collection) {
if (condition(item)) {
collection.remove(item); // unsafe
}
}
Rules
- Enhanced
foruses an iterator internally. - Do not structurally modify a collection during iteration unless using the iterator's own
remove(). ConcurrentModificationExceptioncan happen in a single thread.Iterator.remove()removes the last item returned bynext().- Call
remove()at most once pernext().
FAQ
Why does ConcurrentModificationException happen in one thread?
Because the problem is unsafe modification during iteration, not necessarily multiple threads. One part of the code is iterating while another changes the collection structure.
Is it ever safe to call collection.remove() inside a for-each loop?
Generally no. The safe approach is to use Iterator.remove() or removeIf(...).
What is the best way to remove items from a generic Collection?
Use an Iterator and call iterator.remove() while iterating, or use removeIf(...) in Java 8 and later.
Does removeIf() work for all collections?
It works for many standard Java collections, but the collection must support removal operations. Unsupported collections may throw UnsupportedOperationException.
Why does Java use fail-fast iterators?
To detect unsafe changes early and prevent unpredictable behavior like skipped elements or corrupted traversal.
Can I use a normal index loop instead?
Only if you specifically have a List and index-based access makes sense. For a general , you should not rely on indexing.
Mini Project
Description
Create a small Java program that cleans a collection of integers by removing unwanted values. This demonstrates safe in-place removal using both Iterator and removeIf, which is a common task in data cleanup and validation code.
Goal
Build a program that removes all negative numbers and prints the cleaned collection safely.
Requirements
- Create a
Collection<Integer>with a mix of positive, negative, and zero values. - Remove all negative values safely while iterating.
- Print the collection before and after cleanup.
- Implement at least one solution using
Iterator. - Optionally show a second version using
removeIf.
Keep learning
Related questions
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Choosing a @NotNull Annotation in Java: Validation vs Static Analysis
Learn how Java @NotNull annotations differ, when to use each one, and how to choose between validation, IDE hints, and static analysis tools.
Convert a Java Stack Trace to a String
Learn how to convert a Java exception stack trace to a string using StringWriter and PrintWriter, with examples and common mistakes.