Kako izbeći izuzetak ConcurrentModificationException prilikom iteracije kroz kolekciju?
sobes.tech АИ
Одговор од АИ
За избегавање ConcurrentModificationException при обиласку колекције, можете користити следеће приступе:
-
Користите потокобезбедне колекције:
java.util.concurrentпружа потокобезбедне алтернативе стандардним колекцијама. На пример:CopyOnWriteArrayListуместоArrayListCopyOnWriteArraySetуместоHashSetConcurrentHashMapуместоHashMap
// Пример са 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"); // Итератор не баца `ConcurrentModificationException` Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); // Безбедно је да мењате колекцију током обиласка if (element.equals("B")) { list.remove(element); } } System.out.println("Коначна листа: " + list); } } -
Блокирајте колекцију: Синхронизујте приступ колекцији коришћењем
synchronizedили блокирањаjava.util.concurrent.locks.// Пример са синхронизованим блоком 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) { // Блокирамо колекцију за приступ Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); // Не смете мењати колекцију овде ако други ток може да добије приступ // кроз овај `synchronized` блок } } // Промена колекције изван синхронизованог блока или од другог тока // може и даље изазвати `ConcurrentModificationException` током паралелног обиласка } } -
Користите итератор за брисање елемената: Ако треба да избришете елементе током обиласка, користите метод
remove()самог итератора (ако га колекција подржава).// Пример брисања коришћењем `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); // Безбедно је да уклоните елемент преко итератора if (element.equals("B")) { iterator.remove(); } } System.out.println("Коначна листа: " + list); } } -
Обилазите копију колекције: Направите копију колекције и обилазите је. Промене у оригиналној колекцији неће утицати на обилазак копије.
// Пример обиласка копије 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"); // Креирање копије за обилазак List<String> copyList = new ArrayList<>(list); for (String element : copyList) { System.out.println(element); // Можемо мењати оригиналну колекцију током обиласка копије if (element.equals("B")) { list.remove(element); } } System.out.println("Коначна листа: " + list); } }
Избор приступа зависи од конкретних захтева: да ли је потребно мењати колекцију током обиласка, колико је важна перформанса и да ли код ради у мулти-тред средини. CopyOnWriteArrayList/CopyOnWriteArraySet су погодни када је читање знатно веће од уписа. Блокирање је погодније када се промене дешавају ређе, али могу бити учесталије него код коришћења CopyOnWrite. Користење Iterator.remove() или обилазак копије је прикладно када се промене дешавају само у оквиру једне итерације или тока.