java - ejemplo - ¿Cómo evitar "ConcurrentModificationException" al eliminar elementos de ''ArrayList'' mientras se iteran?
java iterator() (10)
¡No no no!
En las tareas con amenazas individuales no es necesario usar Iterator, además, CopyOnWriteArrayList (debido al impacto de rendimiento).
La solución es mucho más sencilla: intente usar canónico para bucle en lugar de para cada bucle .
De acuerdo con los propietarios de derechos de autor de Java (hace algunos años, Sun, ahora Oracle) para cada guía de bucle , usa iterador para recorrer la colección y solo la oculta para hacer 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 llevará a java.util.ConcurrentModificationException cuando ingrese 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 usar el método de indexación para iterar sobre colecciones y evite cada ciclo, ¡ya que no son equivalentes! Para cada bucle se utilizan algunos iteradores internos, que comprueban la modificación de la colección y emiten la excepción ConcurrentModificationException. Para confirmar esto, eche un vistazo más de cerca al seguimiento de la 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 los subprocesos múltiples, use los enfoques multitarea correspondientes (como palabras clave sincronizadas).
Esta pregunta ya tiene una respuesta aquí:
Estoy tratando de eliminar algunos elementos de un ArrayList
mientras lo itero así:
for (String str : myArrayList) {
if (someCondition) {
myArrayList.remove(str);
}
}
Por supuesto, obtengo una ConcurrentModificationException
cuando intento eliminar elementos de la lista al mismo tiempo cuando se itera myArrayList
. ¿Hay alguna solución simple para resolver este problema?
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.
Debe utilizar el método remove () del iterador, lo que significa que no está mejorado para bucle:
for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) {
iterator.next();
if (someCondition) {
iterator.remove();
}
}
El usuario de Java 8 puede hacer eso: list.removeIf(...)
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
list.removeIf(e -> (someCondition));
Se eliminarán los elementos de la lista, para lo cual se cumple alguna condición.
Puede utilizar la función remove () de 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 here
Si bien otras soluciones sugeridas funcionan, si realmente desea que la solución sea segura para subprocesos, 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);
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.
Un método alternativo es convertir su List
en array
, iterarlos y eliminarlos directamente de la List
según 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());
}
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();
}
}