2011-05-20 14 views
11

Es bastante extraño que este pequeño fragmento de código arroje la Excepción mencionada anteriormente. También, mirar el código publicado en la web esto parece ser correcta:Why Iterator.next() throws ConcurrentModificationException

import java.util.ArrayList; 
import java.util.Iterator; 

public class IteratorTest { 

    ArrayList<Integer> arr = new ArrayList<Integer>(); 

    Iterator i = arr.iterator(); 

    public void show() { 
     arr.add(2); 
     arr.add(5); 
     arr.add(9); 

     while(i.hasNext()){ 
      System.out.println(i.next()); 
     } 
    } 
} 

Algún consejo? Gracias

+0

duplicados de http://stackoverflow.com/questions/223918/iterating-through-a-collection-avoiding-concurrentmodificationexception-when-re – Raedwald

Respuesta

12

Esta llamada:

Iterator i=arr.iterator(); 

deben ser después de haber realizado todas las escrituras en su ArrayList.

Así que en su código de hacer esto justo antes de comenzar la iteración de la siguiente manera:

Iterator i=arr.iterator(); 
while(i.hasNext()) { 
... 
} 
+0

Thx anbhava, así que básicamente iterador no actualizarse si los cambios en la Iterable se realizan. no sabía esto thx – JBoy

+1

Creo que un bucle for es mejor que while loop en que estás limitando el alcance de la variable iteradora 'i'. –

4

Es porque ha modificado la lista de respaldo entre conseguir el iterador a través iterator() y llamando next().

El uso típico de un iterador es:

for (Iterator<Integer> iter=arr.iterator(); iter.hasNext();) { 
    Integer element = iter.next(); 
} 

O mejor aún, utilizar la nueva fines de cada bucle:

for (Integer element: arr) { 
} 

Asegúrese de realizar adiciones a la colección fuera de la lazo.

2

Está definiendo el Iterator al crear su objeto, IteratorTest. A continuación, agregue algunos datos al ArrayList, arr.

Ahora ha modificado su lista, y por lo tanto el estado Iterator no es válido.

No puede usar el Iterator y cambiar el ArrayList sin usar el Iterator para hacerlo.

0

La respuesta 4 es técnicamente correcta, pero no porque se utiliza un bucle for(;;) o "para cada" en lugar de un bucle while(). Simplemente es una cuestión del alcance declarado por el iterador dentro de la Clase en lugar del método. En primer lugar, vamos a ver el comportamiento de los dos métodos hasNext() y next():

El método hasNext() simplemente un cursor consultas interna (índice); next() realmente avanza el cursor, por lo tanto esa es la "modificación" que podría generar la excepción. Si intenta utilizar un iterador declarado y asignado fuera del método en el que se usa next(), el código emitirá una excepción en el primer next(), independientemente de si es un for(;;) o while().

En la respuesta 4 y 8, el iterador se declara y se consume localmente dentro del método. Sucede que dado que el constructo for(;;) permite una primera declaración y asignación de tiempo del iterador antes de que se ejecute el bucle (lo que hace que el iterador alcance el for(;;) e implícitamente dentro del método, lo que lo hace "seguro"). Estoy de acuerdo en que la expresión for(;;) es más clara sintácticamente y delimita el alcance en el nivel más bajo de ejecución, completamente dentro del ciclo for(;;).

La respuesta 8 es correcta, porque el iterador se asigna y utiliza localmente dentro del método.

Pero, sólo por el bien de la discusión, el siguiente método usando una declaración while() es sintácticamente correcta, "seguro" y no modificando desde una perspectiva de alcance y de referencia:

en algún lugar de la definición de clase .. .

ArrayList<String> messageList; 

en alguna parte del constructor de la clase

messageList = new ArrayList<String>(); 

añadir un método ...

public printMessages () 
{ 

    Iterator<String> messageIterator = messageList.iterator(); 

    while (messageIterator.hasNext()) 
    { 
    System.out.println(messageIterator.next()); 
    } 

    System.out.flush(); 

} 
Cuestiones relacionadas