util remove obtener metodos metodo llenar imprimir elemento ejemplos concurrentmodificationexception como clase java arraylist foreach

remove - metodos arraylist java



Cómo evitar java.util.ConcurrentModificationException al iterar y eliminar elementos de una ArrayList (13)

"¿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:

SuppressWarnings("unchecked") public void removeStones() { ArrayList<Stone> clone = (ArrayList<Stone>) stones.clone(); // remove the stones moved to the table for (Stone stone : stones) { if (stone.isOnTable()) { clone.remove(stone); } } stones = (ArrayList<Stone>) clone.clone(); sortStones(); }

Tengo una ArrayList sobre la que quiero iterar. Al iterar sobre él, tengo que eliminar elementos al mismo tiempo. Obviamente, esto arroja una java.util.ConcurrentModificationException .

¿Cuál es la mejor práctica para manejar este problema? ¿Debería clonar la lista primero?

Elimino los elementos que no están 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() ;


Al iterar la lista, si desea eliminar el elemento es posible. Veamos abajo mis ejemplos,

ArrayList<String> names = new ArrayList<String>(); names.add("abc"); names.add("def"); names.add("ghi"); names.add("xyz");

Tengo los nombres anteriores de la lista Array. Y quiero eliminar el nombre "def" de la lista anterior,

for(String name : names){ if(name.equals("def")){ names.remove("def"); } }

El código anterior arroja la excepción ConcurrentModificationException porque está modificando la lista durante la iteración.

Por lo tanto, para eliminar el nombre "def" de Arraylist de esta manera,

Iterator<String> itr = names.iterator(); while(itr.hasNext()){ String name = itr.next(); if(name.equals("def")){ itr.remove(); } }

El código anterior, a través del iterador, podemos eliminar el nombre "def" del Arraylist e intentar imprimir el arreglo, se verá el resultado a continuación.

Salida: [abc, ghi, xyz]


Aquí hay un ejemplo en el que utilizo una lista diferente para agregar los objetos para eliminar, luego uso stream.foreach para eliminar elementos de la lista original:

private ObservableList<CustomerTableEntry> customersTableViewItems = FXCollections.observableArrayList(); ... private void removeOutdatedRowsElementsFromCustomerView() { ObjectProperty<TimeStamp> currentTimestamp = new SimpleObjectProperty<>(TimeStamp.getCurrentTime()); long diff; long diffSeconds; List<Object> objectsToRemove = new ArrayList<>(); for(CustomerTableEntry item: customersTableViewItems) { diff = currentTimestamp.getValue().getTime() - item.timestamp.getValue().getTime(); diffSeconds = diff / 1000 % 60; if(diffSeconds > 10) { // Element has been idle for too long, meaning no communication, hence remove it System.out.printf("- Idle element [%s] - will be removed/n", item.getUserName()); objectsToRemove.add(item); } } objectsToRemove.stream().forEach(o -> customersTableViewItems.remove(o)); }


De los JavaDocs de ArrayList

Los iteradores devueltos por los métodos iterator y listIterator de esta clase no son rápidos: si la lista se modifica estructuralmente en cualquier momento después de que se crea el iterador, de cualquier forma excepto a través de los propios métodos remove o add del iterador, el iterador generará una ConcurrentModificationException.


Dos opciones:

  • Crea una lista de valores que deseas eliminar, agregando a esa lista dentro del ciclo, luego llama a originalList.removeAll(valuesToRemove) al final
  • Use el método remove() 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 cualquier cadena con una longitud mayor a 5 de una lista:

List<String> list = new ArrayList<String>(); ... for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) { String value = iterator.next(); if (value.length() > 5) { iterator.remove(); } }


En Java 8 puede usar la interfaz de colección y hacer esto llamando al método removeIf:

yourList.removeIf((A a) -> a.value == 2);

Más información se puede encontrar here


En lugar de usar Para cada ciclo, use el ciclo normal para. por ejemplo, el siguiente código elimina todos los elementos de la lista de arreglos sin dar java.util.ConcurrentModificationException. Puede modificar la condición en el ciclo de acuerdo con su caso de uso.

for(int i=0;i<abc.size();i++) { e.remove(i); }


Está intentando eliminar el valor de la lista en "bucle forzado" avanzado, lo que no es posible, incluso si aplica algún truco (que hizo en su código). La mejor manera es codificar el nivel del iterador como otro que se recomienda aquí.

Me pregunto cómo la gente no ha sugerido el enfoque tradicional de bucle.

for( int i = 0; i < lStringList.size(); i++ ) { String lValue = lStringList.get( i ); if(lValue.equals("_Not_Required")) { lStringList.remove(lValue); i--; } }

Esto funciona también.


Haz algo simple como este:

for (Object object: (ArrayList<String>) list.clone()) { list.remove(object); }


Realice el ciclo de la manera normal, java.util.ConcurrentModificationException es un error relacionado con los elementos a los que se accede.

Así que prueba:

for(int i = 0; i < list.size(); i++){ lista.get(i).action(); }


Realmente debería iterar la matriz de la manera tradicional

Cada vez que elimine un elemento de la lista, los elementos posteriores avanzarán. Siempre que no cambie los elementos que no sean el iterativo, el siguiente código debería funcionar.

public class Test(){ private ArrayList<A> abc = new ArrayList<A>(); public void doStuff(){ for(int i = (abc.size() - 1); i >= 0; i--) abc.get(i).doSomething(); } public void removeA(A a){ abc.remove(a); } }


Una opción es modificar el método removeA para esto -

public void removeA(A a,Iterator<A> iterator) { iterator.remove(a); }

Pero esto significaría que tu doSomething() debería poder pasar el iterator al método remove . No es una muy buena idea.

¿Puede hacer esto en un enfoque de dos pasos: en el primer ciclo cuando itera sobre la lista, en lugar de eliminar los elementos seleccionados, márquelos como para ser eliminados . Para esto, puede simplemente copiar estos elementos (copia superficial) en otra List .

Luego, una vez que removeAll su iteración, simplemente removeAll todos los elementos de la lista de la primera lista.


Una solución alternativa de Java 8 que utiliza stream:

theList = theList.stream() .filter(element -> !shouldBeRemoved(element)) .collect(Collectors.toList());

En Java 7 puedes usar guayaba en su lugar:

theList = FluentIterable.from(theList) .filter(new Predicate<String>() { @Override public boolean apply(String element) { return !shouldBeRemoved(element); } }) .toImmutableList();

Tenga en cuenta que el ejemplo de Guava da como resultado una lista inmutable que puede ser o no lo que usted desea.