Question
What causes ConcurrentModificationException to be thrown in one loop and not in another when iterating over a collection?
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
for (String s : list) {
if (s.equals("B")) {
list.remove(s); // This will throw ConcurrentModificationException
}
}
for (String s : new ArrayList<>(list)) {
if (s.equals("B")) {
// Safe to remove from this copy
list.remove(s);
}
}
Answer
ConcurrentModificationException in Java occurs when a collection is modified while iterating over it. Understanding the rules of collection modifications can help prevent this exception.
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
if (s.equals("B")) {
iterator.remove(); // Safe removal
}
}
Causes
- Modifying a collection (like adding or removing elements) while iterating through it with a standard iterator, which is not designed for concurrent modification.
- Using the `foreach` loop on a collection which does not allow modification while iterating.
Solutions
- Use an explicit iterator to remove elements safely during iteration with `iterator.remove()` method instead.
- Create a copy of the collection before iterating (as shown in the second loop) to avoid modifying the original collection.
Common Mistakes
Mistake: Modifying the collection directly inside a for-each loop.
Solution: Always prefer using an `Iterator` for safe removal during iteration.
Mistake: Assuming that a copy of the collection can be made implicitly during iteration.
Solution: Explicitly clone or create a new instance of the collection before iterating.
Helpers
- ConcurrentModificationException
- Java collection modification
- iterator remove method
- safe removal in Java
- Java foreach loop modification