Sobes.tech
Middle

Kā izvairīties no izņēmuma ConcurrentModificationException, pārlūkojot kolekciju?

sobes.tech AI

Atbilde no AI

Lai izvairītos no ConcurrentModificationException kolekcijas iterācijas laikā, var izmantot šādus pieejas:

  1. Izmantot sērijai drošas kolekcijas: java.util.concurrent nodrošina sērijai drošas alternatīvas standarta kolekcijām. Piemēram:

    • CopyOnWriteArrayList vietā ArrayList
    • CopyOnWriteArraySet vietā HashSet
    • ConcurrentHashMap vietā HashMap
    // Piemērs ar 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");
    
            // Iterators neizraisa `ConcurrentModificationException`
            Iterator<String> iterator = list.iterator();
            while (iterator.hasNext()) {
                String element = iterator.next();
                System.out.println(element);
                // Kolekcijas maiņa iterācijas laikā ir droša
                if (element.equals("B")) {
                    list.remove(element);
                }
            }
            System.out.println("Galīgais saraksts: " + list);
        }
    }
    
  2. Bloķēt kolekciju: Sinhronizēt piekļuvi kolekcijai, izmantojot synchronized vai java.util.concurrent.locks.

    // Piemērs ar sinhronizētu 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) { // Bloķē kolekciju piekļuvei
               Iterator<String> iterator = list.iterator();
               while (iterator.hasNext()) {
                   String element = iterator.next();
                   System.out.println(element);
                   // Šeit nedrīkst mainīt kolekciju, ja cits pavedienis var piekļūt
               }
           }
           // Kolekcijas maiņa ārpus sinhronizētā bloka vai citā pavedienā
           // joprojām var izraisīt `ConcurrentModificationException`, ja notiek paralēla iterācija
       }
    }
    
  3. Izmantot iteratoru elementu dzēšanai: Ja nepieciešams dzēst elementus iterācijas laikā, izmantojiet remove() metodi no iteratora (ja kolekcija to atbalsta).

    // Piemērs ar `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);
                // Elementa dzēšana ar iteratoru ir droša
                if (element.equals("B")) {
                    iterator.remove();
                }
            }
            System.out.println("Galīgais saraksts: " + list);
        }
    }
    
  4. Iterēt kopiju kolekcijas: Izveidot kopiju un to iterēt. Izmaiņas sākotnējā kolekcijā neietekmēs iterāciju pa kopiju.

    // Piemērs ar kopijas iterāciju
    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");
    
            // Izveidojam kopiju iterācijai
            List<String> copyList = new ArrayList<>(list);
    
            for (String element : copyList) {
                System.out.println(element);
                // Var mainīt oriģinālo kolekciju iterācijas laikā
                if (element.equals("B")) {
                    list.remove(element);
                }
            }
            System.out.println("Galīgais saraksts: " + list);
        }
    }
    

Izvēlētais pieejas veids ir atkarīgs no konkrētajām prasībām: vai ir nepieciešams mainīt kolekciju iterācijas laikā, cik svarīgs ir veiktspējas un vai kods darbojas daudzprocesuālas vides apstākļos. CopyOnWriteArrayList/CopyOnWriteArraySet ir piemēroti, kad lasījumu ir daudz vairāk nekā rakstu. Bloķēšana ir piemērota, kad izmaiņas notiek retāk, bet tās var būt biežākas nekā ar CopyOnWrite. Iterator.remove() vai kopijas iterācija ir piemērotas, kad izmaiņas notiek tikai vienas iterācijas vai pavediena laikā.