65 votes

Obtention d'une exception ConcurrentModificationException lors de la suppression d'un élément de java.util.List lors de l'itération de liste?

 @Test
public void testListCur(){
    List<String> li=new ArrayList<String>();
    for(int i=0;i<10;i++){
        li.add("str"+i);
    }

    for(String st:li){
        if(st.equalsIgnoreCase("str3"))
            li.remove("str3");
    }
    System.out.println(li);
}
 

Lorsque je lance ce code, je vais lancer une exception ConcurrentModificationException.

Il semble que lorsque je supprime l'élément spécifié de la liste, la liste ne sait pas que sa taille a été modifiée.

Je me demande s'il s'agit d'un problème courant lié aux collections et à la suppression d'éléments.

95voto

Paul Blessing Points 2265

Je pense que c’est l’objet de la méthode Iterator.remove () , de pouvoir supprimer un élément de la collection tout en effectuant une itération.

Par exemple:

 Iterator<String> iter = li.iterator();
while(iter.hasNext()){
    if(iter.next().equalsIgnoreCase("str3"))
        iter.remove();
}
 

19voto

Serhiy Points 1399

Notez que cette exception ne signifie pas toujours qu'un objet a été simultanément modifiée par un autre thread. Si un seul thread émet une séquence d'appels de méthode qui viole le contrat d'un objet, l'objet peut lever cette exception. Par exemple, si un thread modifie une collection directement alors qu'il est de parcourir la collection avec un fail-fast itérateur, l'itérateur sera thow cette exception

Prises de http://download.oracle.com/javase/1.4.2/docs/api/java/util/ConcurrentModificationException.html

6voto

hvgotcodes Points 55375

oui des gens courir dans les, le problème est que vous ne pouvez pas modifier la liste lors de l'itération sur elle. J'ai utilisé 2 alternatives dans le passé:

  1. Vous pouvez garder une trace de l'index des éléments que vous souhaitez supprimer, puis de les supprimer après que vous avez terminé l'itération.
  2. Ou vous pouvez copier et de tous ceux que vous souhaitez conserver dans une nouvelle liste que vous parcourez, et ensuite jeter les vieux de la liste lorsque vous avez terminé.

ces options supposent que vous avez pour parcourir la liste pour trouver les éléments à supprimer -- utile dans les cas où les éléments de la liste sont des objets complexes avec des propriétés que vous pouvez faire le test sur.

Dans votre cas particulier, vous n'avez même pas besoin de réitérer, que vous pouvez simplement utiliser removeAll. Regardez l'API ici. Il y a aussi chouette méthodes comme retainAll que jeter tout ce qui n'est pas dans l'argument. Vous pouvez utiliser l'option supprimer/conserver des méthodes à chaque fois que les objets de la liste d'implémenter equals et hashcode correctement. Si vous ne pouvez pas compter sur est égal à/hashcode pour identifier l'égalité entre les instances de votre application, vous aurez à faire le déménagement vous-même....

1voto

gstackoverflow Points 1993

Liste de tableaux a champ modCount - temps de la collecte des modifications

Lorsque vous appelez la méthode iterator() crée un nouvel objet Itr. Il a champ expectedModCount. expectedModCount initialisation de champ en modCount de la valeur. Lorsque vous appelez

li.remove("str3");

modCount par incréments. Lorsque vous essayez d'accéder à l' li via un itérateur vérifie que expectedModCount == modCount

et si elle est fausse jette ConcurrentModificationException

Donc, si vous obtenez itérateur et après la collecte modifié itérateur est considéré comme non valide et que vous ne pouvez pas l'utiliser.

0voto

Envil Points 481

J'ai eu ce problème et je pense que le moyen le plus facile est le même avec la deuxième façon donnée par hvgotcodes.

Vous pouvez également copier tous ceux que vous souhaitez conserver dans une nouvelle liste au fur et à mesure de votre itération, puis supprimer l'ancienne liste une fois l'opération terminée.

 @Test
public void testListCur(){
    List<String> li=new ArrayList<String>();
    for(int i=0;i<10;i++){
        li.add("str"+i);
    }
    List<String> finalLi = new ArrayList<String>();
    for(String st:li){
        if(st.equalsIgnoreCase("str3")){
            // Do nothing
        } else {
            finalLi.add(st);
        }
    }
    System.out.println(finalLi);
}
 

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