2013-06-06 2 views
17

So che se proverei a rimuovere dalla raccolta il looping con il ciclo semplice otterrò questa eccezione: java.util.ConcurrentModificationException. Ma sto usando Iterator e mi genera ancora questa eccezione. Qualche idea sul perché e come risolverlo?java.util.ConcurrentModificationException con iteratore

HashSet<TableRecord> tableRecords = new HashSet<>(); 

... 

    for (Iterator<TableRecord> iterator = tableRecords.iterator(); iterator.hasNext();) { 
     TableRecord record = iterator.next(); 
     if (record.getDependency() == null) { 
      for (Iterator<TableRecord> dependencyIt = tableRecords.iterator(); dependencyIt.hasNext();) { 
       TableRecord dependency = dependencyIt.next(); //Here is the line which throws this exception 
       if (dependency.getDependency() != null && dependency.getDependency().getId().equals(record.getId())) { 
        iterator.remove(); 
       } 
      } 
     } 
    } 

risposta

27

È necessario utilizzare iterator.remove() invece di tableRecords.remove()

È possibile rimuovere gli elementi in un elenco su cui eseguire iterazioni solo se si utilizza il metodo di rimuovere dal iteratore.

EDIT:

Quando si crea un iteratore, si inizia a contare le modifiche che sono state applicate sulla raccolta. Se l'iteratore rileva che alcune modifiche sono state apportate senza utilizzare il suo metodo (o utilizzando un altro iteratore sullo stesso insieme), non può garantire che non passerà due volte sullo stesso elemento o salta uno, quindi genera questa eccezione

ciò significa che è necessario modificare il codice in modo che si rimuove solo articoli via iterator.remove (e con un solo iteratore)

O

fare una lista di elementi da rimuovere poi rimuoverli dopo aver finito l'iterazione .

+0

Ci sono due iteratori annidati in modo che probabilmente non risolvere il problema. – assylias

+2

Ancora lo stesso. – user2219247

+0

@assylias È vero, non ho visto il secondo. Ho aggiunto qualche spiegazione su questa eccezione. –

0

Il contratto per l'iteratore di HashSet è che non è possibile rimuovere dall'hashset se non tramite il metodo di rimozione di questo specifico spettrofotometro. Dal punto di vista di dependencyIt, è stato rimosso un elemento diverso chiamando il suo metodo remove in modo da generare uno ConcurrentModificationException.

Sembra che si voglia rimuovere i record dal proprio hashset quando hanno lo stesso id del record. Non sarebbe più semplice sovrascrivere i metodi equals e hashcode dei record per garantire che i record con lo stesso ID siano uguali e abbiano lo stesso hashcode? (se ciò ha senso, ovviamente)

0

Il problema è che si hanno due iteratori nello scope contemporaneamente e stanno "combattendo" l'uno con l'altro. Il modo più semplice per risolvere il problema è solo quello di salvare il ciclo interno se si trova una corrispondenza:

for (Iterator<TableRecord> iterator = tableRecords.iterator(); iterator.hasNext();) { 
    TableRecord record = iterator.next(); 
    if (record.getDependency() == null) { 
     for (Iterator<TableRecord> dependencyIt = tableRecords.iterator(); dependencyIt.hasNext();) { 
      TableRecord dependency = dependencyIt.next(); //Here is the line which throws this exception 
      if (dependency.getDependency() != null && dependency.getDependency().getId().equals(record.getId())) { 
       iterator.remove(); 
       break; // ADD THIS LINE 
      } 
     } 
    } 
} 

Java Iterator s hanno lo scopo di "fail fast" ogni volta che il loro contenitore sottostante viene modificato senza essere stata modificata utilizzando il Iterator. Stai utilizzando iteratori nidificati, quindi qualsiasi operazione remove() emessa a uno farà sì che l'altro lanci uno Exception se continua a essere utilizzato. Per questo motivo, se è necessario emettere un numero remove(), sarà necessario farlo sull'iteratore "esterno" (che si sta facendo) e interrompere l'uso del secondo iteratore in seguito (a cui fa riferimento l'istruzione break aggiunta).

1

Iterator controlli di proprietà fail-veloci per qualsiasi modifica nella struttura della collezione ogni volta sottostante che cercano di ottenere l'elemento successivo . Se sono state trovate modifiche, genera ConcurrentModificationException. Tutte le implementazioni di Iterator nelle classi Collection sono fail-fast di progettazione eccetto le simultanee classi di raccolta come ConcurrentHashMap e CopyOnWriteArrayList.

Fonte: Google

Avrai a capire meglio con un esempio scritto qui di seguito: -

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Iterator; 
import java.util.List; 

public class IteratorExp { 
    public static void main(String... q) { 
     //CASE - ONE 
     List<String> strList = new ArrayList<>(Arrays.asList("a", "b", "c")); 
     Iterator<String> itr = strList.iterator(); 
     /* 
     * strList.add("e"); strList.add("f"); strList.add("g"); 
     */ 
     while (itr.hasNext()) { 
      System.out.println(itr.next()); 
     } 
     /* 
     * Exception in thread "main" java.util.ConcurrentModificationException 
     * at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at 
     * java.util.ArrayList$Itr.next(Unknown Source) at 
     * IteratorExp.main(IteratorExp.java:14) 
     */ 

     //CASE - TWO 
     List<Integer> intList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)); 
     Iterator<Integer> itrOne = intList.iterator(); 
     Iterator<Integer> itrTwo = intList.iterator(); 
     for (; itrOne.hasNext();) { 
      if (itrOne.next().equals(5)) { 
       itrOne.remove(); // #1 
       //intList.remove(itrOne.next()); // #2 
      } 
     } 
     for (; itrTwo.hasNext();) { 
      if (itrTwo.next().equals(5)) { 
       itrTwo.remove(); // #1 
       //intList.remove(itrTwo.next()); // #2 
      } 
     } 

     /* 
     * Exception in thread "main" java.util.ConcurrentModificationException 
     * at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at 
     * java.util.ArrayList$Itr.next(Unknown Source) at 
     * IteratorExp.main(IteratorExp.java:35) 
     */ 
    } 
} 
Problemi correlati