Kaip išvengti ConcurrentModificationException išimtį kolekcijos peržiūros metu?
sobes.tech AI
Atsakymas iš AI
Norint išvengti ConcurrentModificationException per kolekcijos iteraciją, galima naudoti šiuos metodus:
-
Naudoti srautui saugias kolekcijas:
java.util.concurrentsiūlo srautui saugias alternatyvas standartinėms kolekcijoms. Pavyzdžiui:CopyOnWriteArrayListvietojeArrayListCopyOnWriteArraySetvietojeHashSetConcurrentHashMapvietojeHashMap
// Pavyzdys su 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"); // Iteratorius nemeta `ConcurrentModificationException` Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); // Kolekcijos keitimas iteracijos metu yra saugus if (element.equals("B")) { list.remove(element); } } System.out.println("Galutinis sąrašas: " + list); } } -
Blokuoti kolekciją: Synchronizuoti prieigą prie kolekcijos naudojant
synchronizedarbajava.util.concurrent.locks.// Pavyzdys su sinchronizuotu bloku 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) { // Blokuojame kolekciją prieigos metu Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); // Čia negalima keisti kolekcijos, jei kitas srautas gali prieiti } } // Kolekcijos keitimas už sinchronizuoto bloko arba kito srauto // vis dar gali sukelti `ConcurrentModificationException` jei vyksta lygiagreti iteracija } } -
Naudoti iteratorių elementų šalinimui: Jei reikia šalinti elementus iteracijos metu, naudokite
remove()metodą iš iteratoriaus (jei kolekcija jį palaiko).// Pavyzdys su `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); // Elemento šalinimas per iteratorių yra saugus if (element.equals("B")) { iterator.remove(); } } System.out.println("Galutinis sąrašas: " + list); } } -
Iteruoti kopiją kolekcijos: Sukurti kopiją ir ja iteruoti. Pakeitimai originalioje kolekcijoje neturės įtakos iteracijai.
// Pavyzdys su kopijos iteracija 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"); // Sukuriame kopiją iteracijai List<String> copyList = new ArrayList<>(list); for (String element : copyList) { System.out.println(element); // Galime keisti originalią kolekciją iteracijos metu if (element.equals("B")) { list.remove(element); } } System.out.println("Galutinis sąrašas: " + list); } }
Pasirinktas metodas priklauso nuo konkrečių reikalavimų: ar reikia keisti kolekciją iteracijos metu, kaip svarbu našumas ir ar kodas veikia daugiagijėje aplinkoje. CopyOnWriteArrayList/CopyOnWriteArraySet tinka, kai skaitymų yra daug daugiau nei rašymų. Blokavimas tinka, kai pakeitimai vyksta rečiau, bet gali būti dažnesni nei naudojant CopyOnWrite. Iterator.remove() arba kopijos iteracija yra tinkami, kai pakeitimai vyksta tik vienos iteracijos ar srauto metu.