2010-07-06 17 views
63

Ho il seguente pezzo di codice:ConcurrentModificationException per ArrayList

private String toString(List<DrugStrength> aDrugStrengthList) { 
    StringBuilder str = new StringBuilder(); 
     for (DrugStrength aDrugStrength : aDrugStrengthList) { 
      if (!aDrugStrength.isValidDrugDescription()) { 
       aDrugStrengthList.remove(aDrugStrength); 
      } 
     } 
     str.append(aDrugStrengthList); 
     if (str.indexOf("]") != -1) { 
      str.insert(str.lastIndexOf("]"), "\n   "); 
     } 
    return str.toString(); 
} 

Quando provo a farlo funzionare, ottengo ConcurrentModificationException, qualcuno può spiegare perché succede, anche se il codice è in esecuzione in stesso thread? E come potrei evitarlo?

+3

[si dovrebbe smettere di preoccuparmi e ad amare creduloni.] (Http://blog.stackoverflow.com/2010/11/dr-strangedupe-or-how- i-imparato-to-stop-preoccupante-e-amore-duplicazione /). – Will

+1

Una spiegazione di questa eccezione è che l'iteratore di ArrayList è un iteratore fail-fast; cioè fallirà (lancia un'eccezione) quando rileva che la sua collezione nel frattempo è stata modificata. Rispetto agli iteratori fail-safe che non generano eccezioni di modifica simultanea (ad esempio, sulle raccolte ConcurrentHashMap e CopyOnWriteArrayList) –

risposta

136

Non è possibile rimuovere dalla lista se si sta navigando con "per ogni" ciclo. È possibile utilizzare Iterator. Sostituire:

for (DrugStrength aDrugStrength : aDrugStrengthList) { 
    if (!aDrugStrength.isValidDrugDescription()) { 
     aDrugStrengthList.remove(aDrugStrength); 
    } 
} 

Con:

for (Iterator<DrugStrength> it = aDrugStrengthList.iterator(); it.hasNext();) { 
    DrugStrength aDrugStrength = it.next(); 
    if (!aDrugStrength.isValidDrugDescription()) { 
     it.remove(); 
    } 
} 
+0

la sintassi foreach di java utilizza effettivamente Iterator, alcuni IDE segnalano questa soluzione e propongono di sostituire con il foreach (per (listener MyListener: MyListenerList)) –

+0

@HugoGresse Sì, ma questa è la direzione opposta. Iterator espone 'remove' che è sicuro per la sua iterazione, qualcosa che foreach" perde ". –

+2

non sapevo che grazie @KonradGarus –

5

Durante l'iterazione nel ciclo, si sta tentando di modificare il valore dell'elenco nell'operazione remove(). Ciò comporterà ConcurrentModificationException.

Seguire il codice qui sotto, che vi ottenere quello che vuoi ma non buttare eccezioni

private String toString(List aDrugStrengthList) { 
     StringBuilder str = new StringBuilder(); 
    List removalList = new ArrayList(); 
    for (DrugStrength aDrugStrength : aDrugStrengthList) { 
     if (!aDrugStrength.isValidDrugDescription()) { 
      removalList.add(aDrugStrength); 
     } 
    } 
    aDrugStrengthList.removeAll(removalList); 
    str.append(aDrugStrengthList); 
    if (str.indexOf("]") != -1) { 
     str.insert(str.lastIndexOf("]"), "\n   "); 
    } 
    return str.toString(); 
} 
+0

Perché il downvote? – bragboy

+2

'aDrugStrengthList.removeAll (removeList)' –

+0

@TimBender - grazie modificato la risposta. – bragboy

22

Come le altre risposte dicono, non è possibile rimuovere un elemento da una collezione che stai iterare su . È possibile aggirare questo utilizzando esplicitamente un Iterator e rimuovere l'elemento lì.

Iterator<Item> iter = list.iterator(); 
while(iter.hasNext()) { 
    Item blah = iter.next(); 
    if(...) { 
    iter.remove(); // Removes the 'current' item 
    } 
} 
5

ci dovrebbero ha un fine dell'esecuzione concomitante di interfaccia List supportare tale operazione.

provare java.util.concurrent.CopyOnWriteArrayList.class

+0

Ho avuto lo stesso problema con HashMap, risolto con un'altra implementazione dell'interfaccia Mappa. Dovresti testarlo da solo. Non conosco i dettagli di CopyOnWriteArrayList – idiotgenius

12

mi piace un ordine inverso ciclo for come ad esempio:

int size = list.size(); 
for (int i = size - 1; i >= 0; i--) { 
    if(remove){ 
     list.remove(i); 
    } 
} 

perché non richiede l'apprendimento eventuali nuove strutture di dati o classi.

+0

WOW GRAZIE. Non conoscevo questo trucco. –

Problemi correlati