util una nodo lista eliminar elemento concurrentmodificationexception como java list concurrentmodification

una - java util concurrentmodificationexception null



¿Se lanza una excepción ConcurrentModificationException al eliminar un elemento de una java.util.List durante la iteración de la lista? (11)

@Test public void testListCur(){ List<String> li=new ArrayList<String>(); for(int i=0;i<10;i++){ li.add("str"+i); } for(String st:li){ if(st.equalsIgnoreCase("str3")) li.remove("str3"); } System.out.println(li); }

Cuando ejecuto este código, arrojaré una ConcurrentModificationException.

Parece que cuando elimino el elemento especificado de la lista, la lista no sabe que su tamaño ha sido cambiado.

Me pregunto si este es un problema común con las colecciones y la eliminación de elementos.


Tenga en cuenta que esta excepción no siempre indica que un objeto ha sido modificado simultáneamente por un hilo diferente. Si un único hilo emite una secuencia de invocaciones de métodos que viola el contrato de un objeto, el objeto puede arrojar esta excepción. Por ejemplo, si un hilo modifica una colección directamente mientras itera sobre la colección con un iterador de fail-fast, el iterador mostrará esta excepción

Tomado de http://download.oracle.com/javase/1.4.2/docs/api/java/util/ConcurrentModificationException.html


ArrayList tiene campo modCount - recuento de modificaciones de colección

Cuando invocas el método iterator() crea un nuevo objeto Itr . Tiene el campo expectedModCount . expectedModCount campo expectedModCount inicializa por el valor de modCount . Cuando invocas

li.remove("str3");

incrementos modCount . ¿Cuándo intentas acceder a li mediante el iterador? Comprueba que expectedModCount == modCount

y si es falso lanza ConcurrentModificationException

Por lo tanto, si obtiene el iterador y después de la colección modificada, iterator se considera no válido y no puede usarlo.


Bucle de una manera diferente ...

public void testListCur(){ List<String> li=new ArrayList<String>(); for(int i=0;i<10;i++){ li.add("str"+i); } for(int i=0; i<li.size(); i++) if(li.get(i).equalsIgnoreCase("str3")) li.remove(i--); System.out.println(li); }


Creo que este es el propósito detrás del método Iterator.remove() , para poder eliminar un elemento de la colección mientras se itera.

Por ejemplo:

Iterator<String> iter = li.iterator(); while(iter.hasNext()){ if(iter.next().equalsIgnoreCase("str3")) iter.remove(); }


Creo que la mejor respuesta es de bigdev.de, pero me gustaría agregarle algo (como si el elemento se elimina de una lista, tal vez le gustaría registrarlo en algún lugar o algo):

List<String> list = new ArrayList<>(); list.removeIf(a -> { boolean condition = a.equalsIgnoreCase("some condition"); if(condition) logger.info("Item removed from the list: " + a); return condition; });


Creo que vale la pena mencionar la versión de Java 8

@Test public void testListCur() { List<String> li = new ArrayList<String>(); for (int i = 0; i < 10; i++) { li.add("str" + i); } li = li.stream().filter(st -> !st.equalsIgnoreCase("str3")).collect(Collectors.toList()); System.out.println(li); }


La forma de Java 8 para eliminarlo de la lista sin iterador es:

li.removeIf(<predicate>)

es decir

List<String> li = new ArrayList<String>(); // ... li = li.removeIf(st -> !st.equalsIgnoreCase("str3"));


Obtuve este problema y creo que la manera más fácil es la misma con la segunda forma que dieron los códigos hvgotcodes.

O puede copiar todos los que desee conservar en una nueva lista a medida que itera, y luego descartar la lista anterior cuando haya terminado.

@Test public void testListCur(){ List<String> li=new ArrayList<String>(); for(int i=0;i<10;i++){ li.add("str"+i); } List<String> finalLi = new ArrayList<String>(); for(String st:li){ if(st.equalsIgnoreCase("str3")){ // Do nothing } else { finalLi.add(st); } } System.out.println(finalLi); }


Pruebe esto (Java 8):

list.removeIf(condition);


Puede hacer una copia de la lista desde la que desea eliminar el elemento, directamente en cada bucle. Para mí, esa es la manera más simple. Algo como esto:

for (String stringIter : new ArrayList<String>(myList)) { myList.remove(itemToRemove); }

Espero que te ayude..


sí, las personas se topan con él; el problema es que no se puede modificar la lista mientras se itera sobre ella. He usado 2 alternativas en el pasado:

  1. Puede realizar un seguimiento de los índices de los elementos que desea eliminar y luego eliminarlos una vez que haya terminado de iterar.
  2. O puede copiar todos los que desee conservar en una nueva lista a medida que itera, y luego descartar la lista anterior cuando haya terminado.

Estas opciones suponen que debe iterar sobre la lista para encontrar los elementos que desea eliminar, lo cual es útil en los casos en que los elementos de la lista son objetos complejos con propiedades que puede probar.

En su caso particular, ni siquiera necesita iterar, ya que solo puede usar removeAll. Mira la API here . También hay métodos ingeniosos como retener todo que descartan todo lo que no está en el argumento. Puede usar métodos remove / retain-like siempre que los objetos en la lista implementen equals y hashcode correctamente. Si no puede confiar en equals / hashcode para identificar la igualdad entre instancias en su aplicación, tendrá que hacer la eliminación usted mismo ....