ConcurrentModificationException in Java

Naveen AnamaneniUpdated · 5 min read

ConcurrentModificationException in Java is an unchecked exception that is thrown when a collection is structurally modified (an element is added or removed) while it is being iterated, other than through the iterator itself. Despite its name, it usually has nothing to do with threads: a single loop that removes from the list it's looping over is enough to cause it. In this lesson, you will learn why it happens and the correct ways to avoid it.

Example: The Exception

Let's see an example that removes an element inside a for-each loop.

Cme.java▶ Try it
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;
 
public class Cme {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>(
            List.of("Navika", "Srihitha", "Advitha"));
        try {
            for (String name : names) {
                if (name.equals("Navika")) {
                    names.remove(name);
                }
            }
        } catch (ConcurrentModificationException e) {
            System.out.println("Caught ConcurrentModificationException");
        }
        System.out.println(names);
    }
}
Output
Caught ConcurrentModificationException
[Srihitha, Advitha]

Explanation: The for-each loop uses an iterator behind the scenes. names.remove(name) changes the list without telling that iterator. On the next step, the iterator notices that the list was changed behind its back and throws ConcurrentModificationException. Note that "Navika" was already removed before the exception.

Why It Happens

The iterator notices that the list changed behind its back

Every ArrayList keeps a counter named modCount that increases on every structural change. When an iterator is created, it saves the current value. Each next() checks whether the counter has changed. If it has, the iterator fails fast with the exception, instead of continuing with an unpredictable result.

A Surprising Case: No Exception at All

Removing the second-to-last element doesn't throw:

Silent.java▶ Try it
import java.util.ArrayList;
import java.util.List;
 
public class Silent {
    public static void main(String[] args) {
        List<String> letters = new ArrayList<>(List.of("a", "b", "c"));
        for (String s : letters) {
            if (s.equals("b")) {
                letters.remove(s);
            }
        }
        System.out.println(letters);
    }
}
Output
[a, c]

Explanation: After "b" is removed, the list has 2 elements, and the iterator has already returned 2. So hasNext() returns false, the loop ends, and the check in next() never runs. "c" was never visited. The code looks correct, but it's just as wrong; it only failed silently.

Four Correct Ways

WayExample
removeIfnames.removeIf(n -> n.equals("Navika"));
Iterator's removeit.remove(); inside an iterator loop (see "Iterator and ListIterator in Java")
Collect, then removeGather items in a second list, then call names.removeAll(toRemove) after the loop
Loop over a copyfor (String n : new ArrayList<>(names)) { names.remove(n); }
Fixed.java▶ Try it
import java.util.ArrayList;
import java.util.List;
 
public class Fixed {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>(
            List.of("Navika", "Srihitha", "Advitha"));
        names.removeIf(n -> n.equals("Navika"));
        System.out.println(names);
    }
}
Output
[Srihitha, Advitha]

Common Mistakes

Assuming the exception means a threading bug. In most cases it's a single loop that changes its own collection.

Trusting code that "works" because it didn't throw. It may be skipping elements.

Catching the exception and continuing. Fix the loop instead.

Interview Corner

Why does ConcurrentModificationException occur?

It occurs when a collection is structurally modified while being iterated by means other than the iterator itself, for example calling list.remove inside a for-each loop over that list. Fail-fast iterators compare the collection's modification count with the value they saved, and throw the exception when they differ. It can happen in a single thread.

How can you remove elements from a list while iterating over it?

Use Iterator.remove(), use Collection.removeIf(condition), collect the elements to remove and call removeAll after the loop, or iterate over a copy of the list. For lists shared between threads, use a concurrent collection.

Practice

  1. Easy: Rewrite the Cme example with an explicit Iterator and it.remove().
  2. Harder: Write a loop that adds the upper-case version of each name to the same list. Observe the exception, then fix it by collecting new names in a separate list first.

Quick check: Concurrent modification

4 questions
1When is ConcurrentModificationException thrown?
2What does a fail-fast iterator compare?
3Removing the second-to-last element in a for-each loop:
4Which is a safe way to remove while looping?

Key Takeaways

Was this tutorial helpful?

Lesson 256 of 482