¿Cómo evitar “ConcurrentModificationException” al eliminar elementos de `ArrayList` mientras lo itera?

Estoy tratando de eliminar algunos elementos de una ArrayList mientras lo repito de esta manera:

 for (String str : myArrayList) { if (someCondition) { myArrayList.remove(str); } } 

Por supuesto, obtengo una ConcurrentModificationException cuando bash eliminar elementos de la lista al mismo tiempo al iterar myArrayList . ¿Hay alguna solución simple para resolver este problema?

Use un Iterator y llame a remove() :

 Iterator iter = myArrayList.iterator(); while (iter.hasNext()) { String str = iter.next(); if (someCondition) iter.remove(); } 

Como alternativa a las respuestas de los demás, siempre he hecho algo como esto:

 List toRemove = new ArrayList(); for (String str : myArrayList) { if (someCondition) { toRemove.add(str); } } myArrayList.removeAll(toRemove); 

Esto evitará que tenga que tratar con el iterador directamente, pero requiere otra lista. Siempre he preferido esta ruta por la razón que sea.

El usuario de Java 8 puede hacer eso: list.removeIf(...)

  List list = new ArrayList<>(Arrays.asList("a", "b", "c")); list.removeIf(e -> (someCondition)); 

Eliminará los elementos de la lista, para los que se cumple alguna condición.

Tienes que usar el método remove () del iterador, lo que significa que no hay bucle forzado mejorado:

 for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) { iterator.next(); if (someCondition) { iterator.remove(); } } 

¡No no no!

En tareas de una sola amenaza, no es necesario utilizar Iterator, además, CopyOnWriteArrayList (debido al impacto en el rendimiento).

La solución es mucho más simple: intente usar canónico para el bucle en lugar de para cada bucle .

Según los titulares de derechos de autor de Java (hace algunos años Sun, ahora Oracle) para cada guía de bucle , utiliza un iterador para recorrer la colección y simplemente la oculta para que el código se vea mejor. Pero, desafortunadamente, como podemos ver, produjo más problemas que beneficios, de lo contrario este tema no surgiría.

Por ejemplo, este código dará lugar a java.util.ConcurrentModificationException al ingresar la siguiente iteración en ArrayList modificado:

  // process collection for (SomeClass currElement: testList) { SomeClass founDuplicate = findDuplicates(currElement); if (founDuplicate != null) { uniqueTestList.add(founDuplicate); testList.remove(testList.indexOf(currElement)); } } 

Pero el siguiente código funciona bien:

  // process collection for (int i = 0; i < testList.size(); i++) { SomeClass currElement = testList.get(i); SomeClass founDuplicate = findDuplicates(currElement); if (founDuplicate != null) { uniqueTestList.add(founDuplicate); testList.remove(testList.indexOf(currElement)); i--; //to avoid skipping of shifted element } } 

Por lo tanto, intente utilizar el enfoque de indexación para iterar sobre colecciones y evitar for-each loop, ¡ya que no son equivalentes! For-each loop usa algunos iteradores internos, que verifican la modificación de la colección y lanzan la excepción ConcurrentModificationException. Para confirmar esto, eche un vistazo más de cerca al trazado impreso de la stack cuando use el primer ejemplo que publiqué:

 Exception in thread "main" java.util.ConcurrentModificationException at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372) at java.util.AbstractList$Itr.next(AbstractList.java:343) at TestFail.main(TestFail.java:43) 

Para multihebra, use los enfoques multitareas correspondientes (como la palabra clave sincronizada).

Si bien otras soluciones sugeridas funcionan, si realmente desea que la solución se haga segura, debe reemplazar ArrayList por CopyOnWriteArrayList.

  //List s = new ArrayList<>(); //Will throw exception List s = new CopyOnWriteArrayList<>(); s.add("B"); Iterator it = s.iterator(); s.add("A"); //Below removes only "B" from List while (it.hasNext()) { s.remove(it.next()); } System.out.println(s); 

Un método alternativo es convertir su List en array , repetirlos y eliminarlos directamente de la List función de su lógica.

 List myList = new ArrayList(); // You can use either list or set myList.add("abc"); myList.add("abcd"); myList.add("abcde"); myList.add("abcdef"); myList.add("abcdefg"); Object[] obj = myList.toArray(); for(Object o:obj) { if(condition) myList.remove(o.toString()); } 

Si desea modificar su Lista durante el recorrido, entonces necesita usar el Iterator . Y luego puede usar iterator.remove() para eliminar los elementos durante el recorrido.

 List myArrayList = Collections.synchronizedList(new ArrayList()); //add your elements myArrayList.add(); myArrayList.add(); myArrayList.add(); synchronized(myArrayList) { Iterator i = myArrayList.iterator(); while (i.hasNext()){ Object object = i.next(); } } 

Puede usar la función remove () de iterator para eliminar el objeto del objeto de colección subyacente. Pero en este caso puede eliminar el mismo objeto y no cualquier otro objeto de la lista.

de aquí