¿Cómo evitar la excepción ConcurrentModificationException al recorrer una colección?
sobes.tech AI
Respuesta de la IA
Para evitar ConcurrentModificationException al recorrer una colección, se pueden usar los siguientes enfoques:
-
Usar colecciones seguras para hilos:
java.util.concurrentofrece alternativas seguras para hilos a las colecciones estándar. Por ejemplo:CopyOnWriteArrayListen lugar deArrayListCopyOnWriteArraySeten lugar deHashSetConcurrentHashMapen lugar deHashMap
// Ejemplo con 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"); // El iterador no lanza ConcurrentModificationException Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); // Cambiar la colección durante la iteración es seguro if (element.equals("B")) { list.remove(element); } } System.out.println("Lista final: " + list); } } -
Bloquear la colección: Sincronizar el acceso a la colección usando
synchronizedo bloqueosjava.util.concurrent.locks.// Ejemplo con bloque 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) { // Bloquea la colección para acceso Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); // No se puede modificar la colección aquí si otro hilo puede acceder // a través de este mismo bloque synchronized } } // Modificar la colección fuera del bloque sincronizado o en otro hilo // aún puede causar ConcurrentModificationException durante la iteración paralela } } -
Usar el iterador para eliminar elementos: Si necesitas eliminar elementos durante la iteración, usa el método
remove()del propio iterador (si la colección lo soporta).// Ejemplo de eliminación 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); // Eliminar elemento a través del iterador de forma segura if (element.equals("B")) { iterator.remove(); } } System.out.println("Lista final: " + list); } } -
Recorrer una copia de la colección: Crear una copia de la colección y recorrerla. Los cambios en la colección original no afectarán la iteración sobre la copia.
// Ejemplo de recorrer una copia 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"); // Crear una copia para recorrer List<String> copyList = new ArrayList<>(list); for (String element : copyList) { System.out.println(element); // Podemos modificar la colección original durante el recorrido de la copia if (element.equals("B")) { list.remove(element); } } System.out.println("Lista final: " + list); } }
La elección del enfoque depende de los requisitos específicos: si necesitas modificar la colección durante la iteración, cuán importante es el rendimiento y si el código funciona en un entorno multihilo. CopyOnWriteArrayList/CopyOnWriteArraySet son adecuados cuando hay muchas más lecturas que escrituras. La bloqueo es apropiado cuando los cambios ocurren con menos frecuencia, pero pueden ser más frecuentes que con CopyOnWrite. Usar Iterator.remove() o recorrer una copia es útil cuando los cambios ocurren solo dentro de una misma iteración o hilo.