Sobes.tech
Middle

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:

  1. Naudoti srautui saugias kolekcijas: java.util.concurrent siūlo srautui saugias alternatyvas standartinėms kolekcijoms. Pavyzdžiui:

    • CopyOnWriteArrayList vietoje ArrayList
    • CopyOnWriteArraySet vietoje HashSet
    • ConcurrentHashMap vietoje HashMap
    // 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);
        }
    }
    
  2. Blokuoti kolekciją: Synchronizuoti prieigą prie kolekcijos naudojant synchronized arba java.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
       }
    }
    
  3. 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);
        }
    }
    
  4. 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.