How to avoid the ConcurrentModificationException when iterating over a collection?
sobes.tech AI
Answer from AI
To avoid ConcurrentModificationException when iterating over a collection, you can use the following approaches:
-
Use thread-safe collections:
java.util.concurrentprovides thread-safe alternatives to standard collections. For example:CopyOnWriteArrayListinstead ofArrayListCopyOnWriteArraySetinstead ofHashSetConcurrentHashMapinstead ofHashMap
// Example with CopyOnWriteArrayList import java.util.concurrent.CopyOnWriteArrayList; import java.util.Iterator; public class ConcurrentCollectionExample { public static void main(String[] args) { CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); list.add("A"); list.add("B"); list.add("C"); // Iterator does not throw ConcurrentModificationException Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); // Modifying the collection during iteration is safe if (element.equals("B")) { list.remove(element); } } System.out.println("Final list: " + list); } } -
Lock the collection: Synchronize access to the collection using
synchronizedor locks fromjava.util.concurrent.locks.// Example with synchronized block import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class SynchronizedCollectionExample { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("A"); list.add("B"); list.add("C"); synchronized (list) { // Lock the collection for access Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); // Cannot modify the collection here if another thread might access it // through the same synchronized block } } // Modifying the collection outside the synchronized block or from another thread // may still cause ConcurrentModificationException during parallel iteration } } -
Use iterator for removal: If you need to remove elements during iteration, use the
remove()method of the iterator (if supported by the collection).// Example of removal using Iterator.remove() import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class IteratorRemoveExample { 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 element = iterator.next(); System.out.println(element); // Safe removal of element via iterator if (element.equals("B")) { iterator.remove(); } } System.out.println("Final list: " + list); } } -
Iterate over a copy of the collection: Create a copy of the collection and iterate over it. Changes to the original collection will not affect the iteration over the copy.
// Example of iterating over a copy import java.util.ArrayList; import java.util.List; public class CopyIterationExample { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("A"); list.add("B"); list.add("C"); // Create a copy for iteration List<String> copyList = new ArrayList<>(list); for (String element : copyList) { System.out.println(element); // Can modify the original collection during iteration over the copy if (element.equals("B")) { list.remove(element); } } System.out.println("Final list: " + list); } }
The choice of approach depends on specific requirements: whether you need to modify the collection during iteration, the importance of performance, and whether the code runs in a multithreaded environment. CopyOnWriteArrayList/CopyOnWriteArraySet are suitable when reads significantly outnumber writes. Locking is appropriate when modifications are less frequent but may be more frequent than with CopyOnWrite. Using Iterator.remove() or iterating over a copy is applicable when modifications occur only within a single iteration or thread.