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

7voto

Tacila Points 79

Effectuez la boucle de la manière habituelle, le java.util.ConcurrentModificationException est une erreur liée aux éléments auxquels on accède.

Essayez donc :

for(int i = 0; i < list.size(); i++){
    lista.get(i).action();
}

7voto

Indra K Points 104

Pendant l'itération de la liste, si vous voulez supprimer un élément, c'est possible. Voir ci-dessous mes exemples,

ArrayList<String>  names = new ArrayList<String>();
        names.add("abc");
        names.add("def");
        names.add("ghi");
        names.add("xyz");

J'ai les noms ci-dessus de la liste Array. Et je veux supprimer le nom "def" de la liste ci-dessus,

for(String name : names){
    if(name.equals("def")){
        names.remove("def");
    }
}

Le code ci-dessus lance le ConcurrentModificationException exception car vous modifiez la liste pendant l'itération.

Donc, pour supprimer le nom "def" de Arraylist en procédant de cette façon,

Iterator<String> itr = names.iterator();            
while(itr.hasNext()){
    String name = itr.next();
    if(name.equals("def")){
        itr.remove();
    }
}

Dans le code ci-dessus, grâce à l'itérateur, nous pouvons supprimer le nom "def" de la liste de tableaux et essayer d'imprimer le tableau, vous verrez la sortie ci-dessous.

Sortie : [abc, ghi, xyz].

5voto

serup Points 1432

Voici un exemple où j'utilise une liste différente pour ajouter les objets à supprimer, puis j'utilise ensuite stream.foreach pour supprimer les éléments de la liste originale :

private ObservableList<CustomerTableEntry> customersTableViewItems = FXCollections.observableArrayList();
...
private void removeOutdatedRowsElementsFromCustomerView()
{
    ObjectProperty<TimeStamp> currentTimestamp = new SimpleObjectProperty<>(TimeStamp.getCurrentTime());
    long diff;
    long diffSeconds;
    List<Object> objectsToRemove = new ArrayList<>();
    for(CustomerTableEntry item: customersTableViewItems) {
        diff = currentTimestamp.getValue().getTime() - item.timestamp.getValue().getTime();
        diffSeconds = diff / 1000 % 60;
        if(diffSeconds > 10) {
            // Element has been idle for too long, meaning no communication, hence remove it
            System.out.printf("- Idle element [%s] - will be removed\n", item.getUserName());
            objectsToRemove.add(item);
        }
    }
    objectsToRemove.stream().forEach(o -> customersTableViewItems.remove(o));
}

4voto

Bhaskar Points 3314

Une option consiste à modifier le removeA à cette méthode -

public void removeA(A a,Iterator<A> iterator) {
     iterator.remove(a);
     }

Mais cela signifierait que votre doSomething() devrait être en mesure de passer le iterator à la remove méthode. Ce n'est pas une très bonne idée.

Pouvez-vous faire cela en deux étapes ? Dans la première boucle, lorsque vous itérez sur la liste, au lieu de supprimer les éléments sélectionnés.., marque comme à supprimer . Pour ce faire, vous pouvez simplement copier ces éléments (copie superficielle) dans un autre système d'information. List .

Ensuite, une fois que votre itération est terminée, il suffit de faire un removeAll de la première liste tous les éléments de la deuxième liste.

4voto

Shubham Chopra Points 412

Au lieu d'utiliser la boucle For each, utilisez la boucle for normale. Par exemple, le code ci-dessous supprime tous les éléments de la liste du tableau sans provoquer d'exception java.util.ConcurrentModificationException. Vous pouvez modifier la condition dans la boucle en fonction de votre cas d'utilisation.

for(int i=0; i<abc.size(); i++)  {
       e.remove(i);
 }

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