Cum să eviți excepția ConcurrentModificationException în timpul parcurgerii unei colecții?
sobes.tech AI
Răspuns de la AI
Pentru a evita ConcurrentModificationException în timpul iterării peste o colecție, se pot folosi următoarele abordări:
-
Utilizarea colecțiilor sigure pentru fire de execuție:
java.util.concurrentoferă alternative sigure pentru colecțiile standard. De exemplu:CopyOnWriteArrayListîn loc deArrayListCopyOnWriteArraySetîn loc deHashSetConcurrentHashMapîn loc deHashMap
// Exemplu cu 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 nu aruncă `ConcurrentModificationException` Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); // Modificarea colecției în timpul iterării este sigură if (element.equals("B")) { list.remove(element); } } System.out.println("Lista finală: " + list); } } -
Blocarea colecției: Sincronizați accesul la colecție folosind
synchronizedsau blocuri de blocarejava.util.concurrent.locks.// Exemplu cu bloc sincronizat 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) { // Blocăm colecția pentru acces Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); // Nu se poate modifica colecția aici dacă alt fir de execuție poate avea acces } } // Modificarea colecției în afara blocului sincronizat sau de către alt fir // poate încă provoca `ConcurrentModificationException` în timpul iterării paralele } } -
Utilizarea iteratorului pentru eliminarea elementelor: Dacă trebuie să eliminați elemente în timpul iterării, folosiți metoda
remove()a iteratorului (dacă este suportată de colecție).// Exemplu de eliminare cu 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); // Eliminarea elementului prin iterator este sigură if (element.equals("B")) { iterator.remove(); } } System.out.println("Lista finală: " + list); } } -
Iterarea peste o copie a colecției: Creați o copie a colecției și iterați peste ea. Modificările în colecția originală nu vor afecta iterația.
// Exemplu de iterare peste o copie 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"); // Creăm o copie pentru iterare List<String> copyList = new ArrayList<>(list); for (String element : copyList) { System.out.println(element); // Putem modifica colecția originală în timpul iterării peste copie if (element.equals("B")) { list.remove(element); } } System.out.println("Lista finală: " + list); } }
Alegerea abordării depinde de cerințele specifice: dacă trebuie să modificați colecția în timpul iterării, cât de importantă este performanța și dacă codul rulează într-un mediu multi-thread. CopyOnWriteArrayList/CopyOnWriteArraySet sunt potrivite pentru citiri frecvente și scrieri rare. Blocarea este potrivită pentru modificări mai rare, dar posibil mai frecvente decât cu CopyOnWrite. Utilizarea Iterator.remove() sau iterarea peste o copie este adecvată atunci când modificările se fac doar în cadrul unei singure iterații sau thread.