@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, celle-ci ignore 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.
Je crois 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();
}
La manière dont Java 8 la supprime de la liste sans Iterator est la suivante:
li.removeIf(<predicate>)
c'est à dire.
List<String> li = new ArrayList<String>();
// ...
li = li.removeIf(st -> !st.equalsIgnoreCase("str3"));
Notez que cette exception n'indique pas toujours qu'un objet a été modifié simultanément par un autre thread. Si un seul thread émet une séquence d'appels de méthode qui ne respecte pas le contrat d'un objet, celui-ci peut lever cette exception. Par exemple, si un thread modifie directement une collection alors qu'il parcourt la collection avec un itérateur à échec rapide, l'itérateur renvoie cette exception.
Extrait de http://download.Oracle.com/javase/1.4.2/docs/api/Java/util/ConcurrentModificationException.html
oui, les gens le rencontrent - le problème est que vous ne pouvez pas modifier la liste en la parcourant. J'ai utilisé 2 alternatives dans le passé:
ces options supposent que vous devez parcourir la liste pour rechercher les éléments à supprimer, ce qui est utile dans les cas où les éléments de la liste sont des objets complexes avec des propriétés que vous pouvez tester.
Dans votre cas particulier, vous n'avez même pas besoin de répéter, vous pouvez simplement utiliser removeAll. Regardez l'API ici . Il existe également des méthodes astucieuses telles que keepAll qui rejettent tout ce qui n'est pas dans l'argument. Vous pouvez utiliser des méthodes de type remove/rétention lorsque les objets de la liste implémentent des valeurs égales et que le hashcode est correct. Si vous ne pouvez pas compter sur equals/hashcode pour identifier l'égalité entre les instances de votre application, vous devrez effectuer la suppression vous-même ....
Vous pouvez faire une copie de la liste dont vous voulez supprimer l’élément directement dans chaque boucle. Pour moi, c'est le moyen le plus simple. Quelque chose comme ça:
for (String stringIter : new ArrayList<String>(myList)) {
myList.remove(itemToRemove);
}
J'espère que cela vous aidera ..
Je pense qu'il convient de mentionner la version Java 8
@Test
public void testListCur() {
List<String> li = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
li.add("str" + i);
}
li = li.stream().filter(st -> !st.equalsIgnoreCase("str3")).collect(Collectors.toList());
System.out.println(li);
}
Essayez ceci (Java 8):
list.removeIf(condition);
ArrayList a le champ modCount
- nombre de modifications de la collection
Lorsque vous appelez la méthode iterator()
, créez un nouvel objet Itr
. Il a le champ expectedModCount
. Le champ expectedModCount
est initialisé avec la valeur modCount
. Quand vous invoquez
li.remove("str3");
modCount
incréments. Quand essayez-vous d'accéder à li
via l'itérateur Vérifie que expectedModCount == modCount
et si c'est faux jette ConcurrentModificationException
Par conséquent, si vous obtenez un itérateur et une collection après modification, cet itérateur est considéré comme non valide et vous ne pouvez pas l'utiliser.
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);
}
Je pense que la meilleure réponse est celle de bigdev.de, mais j'aimerais ajouter quelque chose (par exemple, si l'élément est supprimé d'une liste, vous voudrez peut-être vous connecter quelque part ou quelque chose):
List<String> list = new ArrayList<>();
list.removeIf(a -> {
boolean condition = a.equalsIgnoreCase("some condition");
if(condition)
logger.info("Item removed from the list: " + a);
return condition;
});
J'ai bouclé d'une manière différente ...
public void testListCur(){
List<String> li=new ArrayList<String>();
for(int i=0;i<10;i++){
li.add("str"+i);
}
for(int i=0; i<li.size(); i++)
if(li.get(i).equalsIgnoreCase("str3"))
li.remove(i--);
System.out.println(li);
}