¿Cómo evitar "ConcurrentModificationException"mientras se eliminan elementos de 'ArrayList' mientras se itera? [duplicar]
Esta pregunta ya tiene una respuesta aquí:
- Iterar a través de una colección, evitando ConcurrentModificationException al eliminar in loop 24 respuestas
Estoy tratando de eliminar algunos elementos de un ArrayList
mientras lo itera de esta manera:
for (String str : myArrayList) {
if (someCondition) {
myArrayList.remove(str);
}
}
Por supuesto, obtengo un ConcurrentModificationException
cuando intento eliminar elementos de la lista al mismo tiempo que iterando myArrayList
. ¿Hay alguna solución simple para resolver este problema?
10 answers
Utilice un Iterator
y llamar remove()
:
Iterator<String> iter = myArrayList.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-26 16:29:00
Como alternativa a las respuestas de todos los demás, siempre he hecho algo como esto:
List<String> toRemove = new ArrayList<String>();
for (String str : myArrayList) {
if (someCondition) {
toRemove.add(str);
}
}
myArrayList.removeAll(toRemove);
Esto evitará que tenga que lidiar con el iterador directamente, pero requiere otra lista. Siempre he preferido esta ruta por cualquier razón.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-09 04:19:12
El usuario de Java 8 puede hacer eso: list.removeIf(...)
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
list.removeIf(e -> (someCondition));
Eliminará elementos de la lista, para los cuales se cumple alguna condición
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-26 12:11:58
Tienes que usar el método remove () del iterador, lo que significa que no hay bucle for mejorado:
for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) {
iterator.next();
if (someCondition) {
iterator.remove();
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-16 20:54:48
No, no, NO!
En tareas individuales no necesita usar Iterator, además, CopyOnWriteArrayList (debido a un golpe de rendimiento).
La solución es mucho más simple: intente usar el bucle canónico for en lugar de for-each loop.
De acuerdo con los propietarios de derechos de autor de Java (hace algunos años Sun, ahora Oracle) para-cada guía de bucle, utiliza iterador para recorrer la colección y solo lo oculta para hacer que el código se vea mejor. Pero, por desgracia, como podemos ver, produjo más problemas que beneficios, de lo contrario este tema no se plantearía.
Por ejemplo, este código llevará a java.útil.ConcurrentModificationException al ingresar la siguiente iteración en ArrayList modificada:
// 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, trate de utilizar el enfoque de indexación para iterar sobre las colecciones y evitar para-cada bucle, ya que no son equivalentes! For-each loop utiliza algunos iteradores internos, que comprueban la modificación de la colección y el tiro Excepción ConcurrentModificationException. Para confirmar esto, eche un vistazo más de cerca a la traza de pila impresa cuando use el primer ejemplo que he publicado:
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 multihilo utilice los enfoques multitarea correspondientes (como palabra clave sincronizada).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-24 01:05:18
Mientras que otras soluciones sugeridas funcionan, si realmente desea que la solución sea segura para el hilo, debe reemplazar ArrayList con CopyOnWriteArrayList
//List<String> s = new ArrayList<>(); //Will throw exception
List<String> s = new CopyOnWriteArrayList<>();
s.add("B");
Iterator<String> it = s.iterator();
s.add("A");
//Below removes only "B" from List
while (it.hasNext()) {
s.remove(it.next());
}
System.out.println(s);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-26 16:55:51
Un método alternativo es convertir su List
a array
, iterarlos y eliminarlos directamente de la List
basado en su lógica.
List<String> myList = new ArrayList<String>(); // 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());
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-21 12:50:20
Si desea modificar su Lista durante el recorrido, debe usar Iterator
. Y luego puede usar iterator.remove()
para eliminar los elementos durante el recorrido.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-26 16:28:25
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();
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-26 16:48:55
Puede usar la función remove() del iterador 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.
Desde aquí
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-22 16:30:43