Tengo una ArrayList sobre la que quiero iterar. Al iterar sobre él, tengo que eliminar elementos al mismo tiempo. Obviamente esto arroja a java.util.ConcurrentModificationException
.
¿Cuál es la mejor práctica para manejar este problema? ¿Debo clonar la lista primero?
Elimino los elementos no en el bucle en sí, sino en otra parte del código.
Mi código se ve así:
public class Test() {
private ArrayList<A> abc = new ArrayList<A>();
public void doStuff() {
for (A a : abc)
a.doSomething();
}
public void removeA(A a) {
abc.remove(a);
}
}
a.doSomething
podría llamar Test.removeA()
;
Respuestas:
Dos opciones:
originalList.removeAll(valuesToRemove)
al finalremove()
método en el iterador mismo. Tenga en cuenta que esto significa que no puede usar el bucle for mejorado.Como ejemplo de la segunda opción, eliminar de una lista cualquier cadena con una longitud mayor que 5:
fuente
Desde los JavaDocs de ArrayList
fuente
Está intentando eliminar el valor de la lista en el "bucle for" avanzado, lo cual no es posible, incluso si aplica algún truco (que hizo en su código). La mejor manera es codificar el nivel de iterador como se recomienda aquí.
Me pregunto cómo la gente no ha sugerido el enfoque tradicional de bucle.
Esto también funciona.
fuente
Realmente deberías repetir la matriz de la manera tradicional
Cada vez que elimine un elemento de la lista, los elementos posteriores se impulsarán. Mientras no cambie elementos que no sean el iterativo, el siguiente código debería funcionar.
fuente
En Java 8 puede usar la interfaz de colección y hacer esto llamando al método removeIf:
Más información se puede encontrar aquí
fuente
Haga el bucle de la manera normal,
java.util.ConcurrentModificationException
es un error relacionado con los elementos a los que se accede.Entonces intenta:
fuente
java.util.ConcurrentModificationException
no quitando nada de la lista. Difícil. :) Realmente no se puede llamar a esto "la forma normal" para iterar una lista.Mientras itera la lista, si desea eliminar el elemento es posible. Veamos a continuación mis ejemplos,
Tengo los nombres anteriores de la lista Array. Y quiero eliminar el nombre "def" de la lista anterior,
El código anterior arroja la excepción ConcurrentModificationException porque está modificando la lista mientras itera.
Entonces, para eliminar el nombre "def" de Arraylist haciendo esto,
El código anterior, a través del iterador, podemos eliminar el nombre "def" de la Arraylist e intentar imprimir la matriz, verá el resultado a continuación.
Salida: [abc, ghi, xyz]
fuente
Una opción es modificar el
removeA
método para esto:Pero esto significaría que
doSomething()
debería poder pasariterator
elremove
método. No es una muy buena idea.¿Puede hacer esto en un enfoque de dos pasos ?: En el primer bucle, cuando itera sobre la lista, en lugar de eliminar los elementos seleccionados, márquelos como eliminados . Para esto, simplemente puede copiar estos elementos (copia superficial) en otro
List
.Luego, una vez que haya terminado su iteración, simplemente haga una
removeAll
desde la primera lista todos los elementos en la segunda lista.fuente
Aquí hay un ejemplo en el que uso una lista diferente para agregar los objetos para su eliminación, luego uso stream.foreach para eliminar elementos de la lista original:
fuente
En lugar de usar Para cada ciclo, use normal para ciclo. por ejemplo, el siguiente código elimina todos los elementos en la lista de matriz sin dar java.util.ConcurrentModificationException. Puede modificar la condición en el bucle según su caso de uso.
fuente
Haga algo simple como esto:
fuente
Una solución alternativa de Java 8 usando stream:
En Java 7 puedes usar Guava en su lugar:
Tenga en cuenta que el ejemplo de Guava da como resultado una lista inmutable que puede o no ser lo que desea.
fuente
También puede usar CopyOnWriteArrayList en lugar de una ArrayList. Este es el último enfoque recomendado por JDK 1.5 en adelante.
fuente
En mi caso, la respuesta aceptada no funciona, detiene la excepción, pero causa algunas inconsistencias en mi lista. La siguiente solución me funciona perfectamente.
En este código, agregué los elementos para eliminar, en otra lista y luego usé el
list.removeAll
método para eliminar todos los elementos necesarios.fuente
"¿Debería clonar la lista primero?"
Esa será la solución más fácil, eliminar del clon y copiar el clon de nuevo después de la eliminación.
Un ejemplo de mi juego rummikub:
fuente
stones = (...) clone.clone();
sea superfluo. ¿Nostones = clone;
haría lo mismo?stones
. De esta manera, ni siquiera necesita laclone
variable:for (Stone stone : (ArrayList<Stone>) stones.clone()) {...
Si su objetivo es eliminar todos los elementos de la lista, puede iterar sobre cada elemento y luego llamar:
fuente
Llego tarde, lo sé, pero respondo esto porque creo que esta solución es simple y elegante:
Todo esto es para actualizar de una lista a otra y puede hacer todo desde una sola lista y, en la actualización del método, verifica ambas listas y puede borrar o agregar elementos entre la lista. Esto significa que ambas listas siempre tienen el mismo tamaño
fuente
Utilice el iterador en lugar de la lista de matrices
Hacer que un conjunto se convierta en iterador con coincidencia de tipos
Y pasar al siguiente elemento y eliminar
Pasar al siguiente es importante aquí, ya que debería tomar el índice para eliminar el elemento.
fuente
¿Qué hay de
fuente
Simplemente agregue un descanso después de su declaración ArrayList.remove (A)
fuente