Como evitar a exceção ConcurrentModificationException ao percorrer uma coleção?
sobes.tech IA
Resposta da IA
Para evitar ConcurrentModificationException ao percorrer uma coleção, pode usar as seguintes abordagens:
-
Usar coleções seguras para threads:
java.util.concurrentfornece alternativas seguras para threads às coleções padrão. Por exemplo:CopyOnWriteArrayListem vez deArrayListCopyOnWriteArraySetem vez deHashSetConcurrentHashMapem vez deHashMap
// Exemplo com 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"); // O iterador não lança ConcurrentModificationException Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); // Alterar a coleção durante a iteração é seguro if (element.equals("B")) { list.remove(element); } } System.out.println("Lista final: " + list); } } -
Bloquear a coleção: Sincronizar o acesso à coleção usando
synchronizedou bloqueiosjava.util.concurrent.locks.// Exemplo com bloco sincronizado 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) { // Bloqueia a coleção para acesso Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); // Não é possível modificar a coleção aqui se outro thread puder acessá-la // através deste mesmo bloco synchronized } } // Modificar a coleção fora do bloco sincronizado ou em outro thread // ainda pode causar ConcurrentModificationException durante a iteração paralela } } -
Usar o iterador para remover elementos: Se precisar remover elementos durante a iteração, use o método
remove()do próprio iterador (se suportado pela coleção).// Exemplo de remoção usando 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); // Remover elemento através do iterador de forma segura if (element.equals("B")) { iterator.remove(); } } System.out.println("Lista final: " + list); } } -
Percorrer uma cópia da coleção: Criar uma cópia da coleção e percorrê-la. As alterações na coleção original não afetarão a iteração sobre a cópia.
// Exemplo de percorrer uma cópia 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"); // Criar uma cópia para percorrer List<String> copyList = new ArrayList<>(list); for (String element : copyList) { System.out.println(element); // Podemos modificar a coleção original durante a iteração da cópia if (element.equals("B")) { list.remove(element); } } System.out.println("Lista final: " + list); } }
A escolha da abordagem depende dos requisitos específicos: se precisa modificar a coleção durante a iteração, quão importante é o desempenho e se o código funciona em um ambiente multithread. CopyOnWriteArrayList/CopyOnWriteArraySet são adequados quando há muitas mais leituras do que gravações. O bloqueio é apropriado quando as mudanças ocorrem com menos frequência, mas podem ser mais frequentes do que com CopyOnWrite. O uso de Iterator.remove() ou percorrer uma cópia é útil quando as mudanças ocorrem apenas dentro de uma única iteração ou thread.