遍历集合添加元素时抛出ConcurrentModificationException异常的原因及解决方法咨询
ConcurrentModificationException Happens & How to Fix It Alright, let's break down exactly what's going on here and how to fix that frustrating exception.
The Root Cause
Java's ArrayList uses a fail-fast iterator—this means the iterator keeps track of the collection's internal modification state from the moment it's created. If the collection's structure changes (like sorting, adding, or removing elements) after the iterator is made, the iterator will detect this mismatch and throw an exception to avoid unsafe iteration over a modified collection.
Here's the play-by-play in your code:
- You create the
ArrayListand add elements to it. - You grab an iterator with
list.iterator()—at this point, the iterator stores a copy of the list's internal modification counter (modCount). - You call
Collections.sort(list)—this rearranges the list's elements, which updates the list'smodCount(since it's a structural change). - When you try to use the original iterator with
itr.hasNext()/itr.next(), the iterator notices its storedexpectedModCountdoesn't match the list's currentmodCount—so it throwsConcurrentModificationExceptionto prevent you from iterating over a collection that's changed out from under you.
Solutions
Let's go through the most practical fixes, ordered by how often you'll need them:
1. Sort Before Getting the Iterator (Best Practice)
This is the simplest and most logical fix. If you need to iterate over the sorted list, just sort first, then create your iterator. This way, the iterator is built on the final, sorted collection, so no structural changes happen after it's created.
Modified code:
public void show() { final ArrayList<String> list = new ArrayList<String>(); list.add("banana"); list.add("apple"); // Sort first, then get the iterator Collections.sort(list); Iterator<String> itr = list.iterator(); while (itr.hasNext()) { System.out.println(itr.next() + " "); } }
2. Recreate the Iterator After Modifying the List
If for some reason you absolutely need to create the iterator first (though this is rare in this sort of scenario), you can just grab a new iterator after the sort. This new iterator will use the updated modCount from the sorted list.
Modified code:
public void show() { final ArrayList<String> list = new ArrayList<String>(); list.add("banana"); list.add("apple"); Iterator<String> itr = list.iterator(); Collections.sort(list); // Get a fresh iterator after the structural change itr = list.iterator(); while (itr.hasNext()) { System.out.println(itr.next() + " "); } }
3. Use a CopyOnWriteArrayList (For Concurrent Scenarios)
If you're working in a multi-threaded environment where the list might be modified while you're iterating, CopyOnWriteArrayList is a good option. It creates a snapshot of the list when you get the iterator—so even if the list is modified later, the iterator will keep working with the original snapshot (note: this means you won't see the sorted changes in the original iterator, so you'd still need a new iterator if you want the sorted data).
Example code:
import java.util.Collections; import java.util.Iterator; import java.util.concurrent.CopyOnWriteArrayList; public class Outputs { public void show() { final CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); list.add("banana"); list.add("apple"); Iterator<String> itr = list.iterator(); Collections.sort(list); // This will iterate over the UNSORTED snapshot (original state) while (itr.hasNext()) { System.out.println(itr.next() + " "); } // Get a new iterator to see the sorted list Iterator<String> sortedItr = list.iterator(); while (sortedItr.hasNext()) { System.out.println(sortedItr.next() + " "); } } }
内容的提问来源于stack exchange,提问作者Ripal Bhagat

