79 votes

ConcurrentModificationException pour ArrayList

J'ai le morceau de code suivant :

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();
}

Quand j'essaie de l'exécuter, j'obtiens ConcurrentModificationException Quelqu'un peut-il expliquer pourquoi cela se produit, même si le code est exécuté dans le même thread ? Et comment puis-je l'éviter ?

163voto

Konrad Garus Points 19280

Vous ne pouvez pas supprimer une liste si vous la parcourez avec une boucle "for each". Vous pouvez utiliser Iterator . Remplacer :

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

Avec :

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

25voto

scompt.com Points 11304

Comme le disent les autres réponses, vous ne pouvez pas supprimer un élément d'une collection sur laquelle vous êtes en train d'itérer. Vous pouvez contourner ce problème en utilisant explicitement une fonction Iterator et de retirer l'élément à cet endroit.

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

16voto

froman Points 59

J'aime bien un ordre inverse pour les boucles comme :

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

car elle ne nécessite pas l'apprentissage de nouvelles structures de données ou de classes.

8voto

idiotgenius Points 41

Il devrait y avoir une implémentation concurrente de l'interface List supportant une telle opération.

essayez java.util.concurrent.CopyOnWriteArrayList.class

6voto

bragboy Points 13615

En itérant dans la boucle, vous essayez de modifier la valeur de la liste dans l'opération remove(). Cela entraînera une ConcurrentModificationException.

Suivez le code ci-dessous, qui vous permettra d'obtenir ce que vous voulez et qui ne lèvera aucune exception.

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();
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X