250 votes

Comment éviter l'exception java.util.ConcurrentModificationException lors de l'itération et de la suppression d'éléments d'une ArrayList ?

J'ai une liste de tableaux que je veux parcourir par itération. Pendant cette itération, je dois supprimer des éléments en même temps. Évidemment, cela génère un java.util.ConcurrentModificationException .

Quelle est la meilleure pratique pour gérer ce problème ? Devrais-je d'abord cloner la liste ?

Je supprime les éléments non pas dans la boucle elle-même mais dans une autre partie du code.

Mon code ressemble à ceci :

public class Test() {
    private ArrayList<A> abc = new ArrayList<A>();

    public void doStuff() {
        for (A a : abc) 
        a.doSomething();
    }

    public void removeA(A a) {
        abc.remove(a);
    }
}

a.doSomething pourrait appeler Test.removeA() ;

385voto

Jon Skeet Points 692016

Deux options :

  • Créez une liste des valeurs que vous souhaitez supprimer, en ajoutant à cette liste dans la boucle, puis appeler originalList.removeAll(valuesToRemove) à la fin
  • Utilisez le remove() sur l'itérateur lui-même. Notez que cela signifie que vous ne pouvez pas utiliser la boucle for améliorée.

À titre d'exemple de la deuxième option, supprimez d'une liste toutes les chaînes de caractères dont la longueur est supérieure à 5 :

List<String> list = new ArrayList<String>();
...
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
    String value = iterator.next();
    if (value.length() > 5) {
        iterator.remove();
    }
}

27voto

Varun Achar Points 5781

Extrait des JavaDocs de ArrayList

Les itérateurs retournés par les méthodes iterator et listIterator de cette classe sont infaillibles : si la liste est structurellement modifiée à tout moment après la création de l'itérateur, de quelque manière que ce soit, sauf par le biais des méthodes de suppression ou d'ajout de l méthodes de suppression ou d'ajout de l'itérateur. l'itérateur lèvera une ConcurrentModificationException.

20voto

suhas0sn07 Points 469

Vous essayez de supprimer une valeur de la liste dans une "boucle for" avancée, ce qui n'est pas possible, même si vous appliquez une astuce (ce que vous avez fait dans votre code). Le meilleur moyen est de coder au niveau de l'itérateur comme d'autres l'ont conseillé ici.

Je me demande comment les gens n'ont pas suggéré l'approche traditionnelle en boucle.

for( int i = 0; i < lStringList.size(); i++ )
{
    String lValue = lStringList.get( i );
    if(lValue.equals("_Not_Required"))
    {
         lStringList.remove(lValue);
         i--; 
    }  
}

Cela fonctionne également.

15voto

ggeo Points 416

En Java 8, vous pouvez utiliser l'interface de collection et faire cela en appelant la méthode removeIf :

yourList.removeIf((A a) -> a.value == 2);

Vous trouverez de plus amples informations ici

11voto

Marcus Points 111

Vous devriez simplement itérer le tableau de la manière traditionnelle.

Chaque fois que vous retirez un élément de la liste, les éléments suivants sont poussés vers l'avant. Tant que vous ne modifiez pas les éléments autres que celui qui est itéré, le code suivant devrait fonctionner.

public class Test(){
    private ArrayList<A> abc = new ArrayList<A>();

    public void doStuff(){
        for(int i = (abc.size() - 1); i >= 0; i--) 
            abc.get(i).doSomething();
    }

    public void removeA(A a){
        abc.remove(a);
    }
}

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