ConcurrentModificationException in Java and How to Prevent It
Introduction
ConcurrentModificationException
is a runtime exception that occurs when a collection is structurally modified
while iterating over it in a way that violates the expected behavior of the iterator. This often happens
when a collection is modified directly (e.g., by adding, removing, or updating elements)
while iterating through it using loops or iterators.
Causes of ConcurrentModificationException
The most common cause of this exception is modifying a collection during iteration without using a safe approach.
For example, calling add()
, remove()
, or put()
on a collection while an iterator is traversing through it.
Java’s ArrayList
, HashSet
, and HashMap
are examples of collections that can trigger this exception
if modified during iteration.
Example: Failing Scenario
Here’s an example that demonstrates how ConcurrentModificationException can occur:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.ArrayList;
import java.util.List;
public class ConcurrentModificationExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
// Iterating over the list
for (String item : list) {
// Attempt to modify the list during iteration
if ("B".equals(item)) {
list.remove(item); // This will throw ConcurrentModificationException
}
}
}
}
In this example, when trying to remove an element from the list during iteration, Java throws a ConcurrentModificationException because the collection was modified while it was being iterated.
Internal Working of Fail-Fast Mechanism
Java’s fail-fast iterators are designed to throw this exception to prevent unexpected behavior.
When a collection is created, an internal counter (known as modCount
) is initialized.
Every structural modification to the collection increments this counter.
When an iterator is created, it takes a snapshot of the modCount
.
During iteration, if it detects any changes to the modCount
, it throws a ConcurrentModificationException
.
This mechanism ensures that concurrent modification issues are caught early rather than resulting in inconsistent data during runtime.
Solutions to Avoid ConcurrentModificationException
There are several ways to avoid ConcurrentModificationException while modifying a collection during iteration:
1. Use Iterator.remove()
Instead of modifying the collection directly, use the remove()
method provided by the iterator:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class SafeRemovalExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if ("B".equals(item)) {
iterator.remove(); // Safely removes element during iteration
}
}
}
}
2. Use CopyOnWriteArrayList
Java provides thread-safe alternatives to certain collections, such as CopyOnWriteArrayList
.
This collection creates a copy of the array whenever it’s modified, allowing safe iteration even when
the collection is being concurrently modified.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class CopyOnWriteExample {
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<>();
list.add("A");
list.add("B");
list.add("C");
// Iterating and modifying the list safely
for (String item : list) {
if ("B".equals(item)) {
list.remove(item); // No ConcurrentModificationException
}
}
}
}
3. Use a for Loop with Index Manipulation
If the collection is a List
, using a for
loop with index manipulation allows you to safely remove elements
without causing the exception.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.ArrayList;
import java.util.List;
public class SafeIndexRemovalExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
for (int i = 0; i < list.size(); i++) {
if ("B".equals(list.get(i))) {
list.remove(i);
i--; // Adjust the index after removal
}
}
}
}
Conclusion
ConcurrentModificationException is a common issue that developers encounter when modifying collections during iteration.
While the fail-fast mechanism helps prevent inconsistencies, it’s important to use the correct approach
for modifying collections. Depending on your scenario, you can use Iterator.remove()
,
thread-safe collections like CopyOnWriteArrayList
, or index-based iteration to avoid this exception.
Understanding these strategies ensures that your code is safe and efficient when working with Java collections.