J'ai un ArrayList que je veux parcourir. En itérant, je dois supprimer des éléments en même temps. Évidemment, cela jette un Java.util.ConcurrentModificationException
.
Quelle est la meilleure pratique pour gérer ce problème? Dois-je d'abord cloner la liste?
Je supprime les éléments non pas dans la boucle 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()
;
Deux options:
originalList.removeAll(valuesToRemove)
à la fin.remove()
sur l'itérateur lui-même. Notez que cela signifie que vous ne pouvez pas utiliser la boucle for améliorée.Comme exemple de la deuxième option, supprimer toutes les chaînes d'une longueur supérieure à 5 de la liste:
List<String> list = new ArrayList<String>();
...
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String value = iterator.next();
if (value.length() > 5) {
iterator.remove();
}
}
À partir des JavaDocs de ArrayList
Les itérateurs retournés par les itérateurs et listIterator de cette classe les méthodes sont fail-fast: si la liste est structurellement modifiée à n’importe quel temps après la création de l'itérateur, de quelque manière que ce soit, sauf par le biais du fichier les méthodes propres à supprimer ou à ajouter de l'itérateur , l'itérateur jettera un ConcurrentModificationException.
Vous devriez vraiment juste réitérer le tableau de la manière traditionnelle
Chaque fois que vous supprimez un élément de la liste, les éléments suivants seront activés. Tant que vous ne modifiez pas d'autres éléments 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);
}
}
Vous essayez de supprimer la valeur de la liste dans la commande avancée "for loop", ce qui n’est pas possible, même si vous appliquez une astuce (que vous avez utilisée dans votre code) . Le meilleur moyen consiste à coder le niveau de l’itérateur comme indiqué ici.
Je me demande comment les gens n'ont pas suggéré l'approche traditionnelle de la 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 aussi bien.
Faites la boucle normalement, le Java.util.ConcurrentModificationException
est une erreur liée aux éléments auxquels vous accédez.
Alors essayez:
for(int i = 0; i < list.size(); i++){
lista.get(i).action();
}
Voici un exemple où j'utilise une liste différente pour ajouter les objets à supprimer, puis j'utilise stream.foreach pour supprimer des éléments de la liste d'origine:
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));
}
Dans Java 8, vous pouvez utiliser l'interface de collection et appelez la méthode removeIf:
yourList.removeIf((A a) -> a.value == 2);
Plus d'informations peuvent être trouvées ici
Une option consiste à modifier la méthode removeA
en ceci -
public void removeA(A a,Iterator<A> iterator) {
iterator.remove(a);
}
Mais cela signifierait que votre doSomething()
devrait pouvoir passer la iterator
à la méthode remove
. Ce n'est pas une bonne idée.
Pouvez-vous le faire en deux étapes: Dans la première boucle lorsque vous parcourez la liste, au lieu de supprimer les éléments sélectionnés, marque comme à supprimer. Pour cela, vous pouvez simplement copier ces éléments (copie superficielle) dans une autre List
.
Ensuite, une fois que votre itération est terminée, faites simplement une removeAll
dans la première liste de tous les éléments de la deuxième liste.
Faites quelque chose de simple comme ça:
for (Object object: (ArrayList<String>) list.clone()) {
list.remove(object);
}
Au lieu d'utiliser Pour chaque boucle, utilisez normal pour boucle. par exemple, le code ci-dessous supprime tous les éléments de la liste de tableaux sans donner 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);
}
Vous pouvez également utiliser CopyOnWriteArrayList au lieu d'un ArrayList. C'est la dernière approche recommandée à partir de JDK 1.5.
En itérant la liste, il est possible de supprimer l'élément. Voyons 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 de tableau. 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 lève l'exception ConcurrentModificationException parce que vous modifiez la liste lors de 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();
}
}
Le code ci-dessus, par itérateur, nous pouvons supprimer le nom "def" de la liste et essayer d'imprimer le tableau, vous verrez la sortie ci-dessous.
Sortie: [abc, ghi, xyz]
Si votre objectif est de supprimer tous les éléments de la liste, vous pouvez effectuer une itération sur chaque élément, puis appeler:
list.clear()
Utiliser Iterator au lieu de Array List
Faire convertir un ensemble en itérateur avec correspondance de type
Et passer à l'élément suivant et supprimer
Iterator<Insured> itr = insuredSet.iterator();
while (itr.hasNext()) {
itr.next();
itr.remove();
}
Passer à la suivante est important ici car il devrait prendre l’index pour supprimer un élément.
J'arrive tard je sais mais je réponds parce que je pense que cette solution est simple et élégante:
List<String> listFixed = new ArrayList<String>();
List<String> dynamicList = new ArrayList<String>();
public void fillingList() {
listFixed.add("Andrea");
listFixed.add("Susana");
listFixed.add("Oscar");
listFixed.add("Valeria");
listFixed.add("Kathy");
listFixed.add("Laura");
listFixed.add("Ana");
listFixed.add("Becker");
listFixed.add("Abraham");
dynamicList.addAll(listFixed);
}
public void updatingListFixed() {
for (String newList : dynamicList) {
if (!listFixed.contains(newList)) {
listFixed.add(newList);
}
}
//this is for add elements if you want eraser also
String removeRegister="";
for (String fixedList : listFixed) {
if (!dynamicList.contains(fixedList)) {
removeResgister = fixedList;
}
}
fixedList.remove(removeRegister);
}
Tout cela sert à mettre à jour une liste à l’autre et vous pouvez tout créer à partir d’une seule liste Dans la méthode de mise à jour, vous vérifiez les deux listes et vous pouvez effacer ou ajouter des éléments entre des listes .
Une solution Java 8 alternative utilisant stream:
theList = theList.stream()
.filter(element -> !shouldBeRemoved(element))
.collect(Collectors.toList());
En Java 7, vous pouvez utiliser Guava à la place:
theList = FluentIterable.from(theList)
.filter(new Predicate<String>() {
@Override
public boolean apply(String element) {
return !shouldBeRemoved(element);
}
})
.toImmutableList();
Notez que l'exemple de goyave donne une liste immuable qui peut être ou ne pas être ce que vous voulez.
"Dois-je d'abord cloner la liste?"
Ce sera la solution la plus simple, retirez-le du clone et copiez-le à nouveau après son retrait.
Un exemple de mon jeu de rummikub:
SuppressWarnings("unchecked")
public void removeStones() {
ArrayList<Stone> clone = (ArrayList<Stone>) stones.clone();
// remove the stones moved to the table
for (Stone stone : stones) {
if (stone.isOnTable()) {
clone.remove(stone);
}
}
stones = (ArrayList<Stone>) clone.clone();
sortStones();
}