1301 Stimmen

Iteration durch eine Sammlung, Vermeidung von ConcurrentModificationException beim Entfernen von Objekten in einer Schleife

Wir alle wissen, dass Sie Folgendes nicht tun können, weil ConcurrentModificationException :

for (Object i : l) {
    if (condition(i)) {
        l.remove(i);
    }
}

Aber das funktioniert offenbar manchmal, aber nicht immer. Hier ist ein spezieller Code:

public static void main(String[] args) {
    Collection<Integer> l = new ArrayList<>();

    for (int i = 0; i < 10; ++i) {
        l.add(4);
        l.add(5);
        l.add(6);
    }

    for (int i : l) {
        if (i == 5) {
            l.remove(i);
        }
    }

    System.out.println(l);
}

Das führt natürlich dazu, dass:

Exception in thread "main" java.util.ConcurrentModificationException

Auch wenn mehrere Threads dies nicht tun. Wie auch immer.

Was ist die beste Lösung für dieses Problem? Wie kann ich ein Element aus der Sammlung in einer Schleife entfernen, ohne diese Ausnahme auszulösen?

Ich verwende auch eine willkürliche Collection hier, nicht unbedingt ein ArrayList Sie können sich also nicht auf get .

1 Stimmen

Hinweis an die Leser: Lesen Sie unbedingt die docs.oracle.com/javase/tutorial/collections/interfaces/ kann es einen einfacheren Weg geben, um das zu erreichen, was Sie tun wollen.

19voto

Landei Punkte 53286

In solchen Fällen ist (war?) ein gängiger Trick, rückwärts zu gehen:

for(int i = l.size() - 1; i >= 0; i --) {
  if (l.get(i) == 5) {
    l.remove(i);
  }
}

Allerdings bin ich mehr als froh, dass es in Java 8 bessere Möglichkeiten gibt, z. B. removeIf o filter auf Strömen.

2 Stimmen

Das ist ein guter Trick. Aber es würde nicht auf nicht-indizierte Sammlungen wie Sets arbeiten, und es wäre wirklich langsam auf sagen, verknüpfte Listen.

0 Stimmen

@Claudiu Ja, das ist definitiv nur für ArrayList s oder ähnliche Sammlungen.

0 Stimmen

Ich verwende eine ArrayList, dies funktionierte perfekt, danke.

17voto

Antzi Punkte 12265

Dieselbe Antwort wie Claudius mit einer for-Schleife:

for (Iterator<Object> it = objects.iterator(); it.hasNext();) {
    Object object = it.next();
    if (test) {
        it.remove();
    }
}

12voto

Priyank Doshi Punkte 12387

Erstellen Sie eine Kopie der vorhandenen Liste und iterieren Sie über die neue Kopie.

for (String str : new ArrayList<String>(listOfStr))     
{
    listOfStr.remove(/* object reference or index */);
}

20 Stimmen

Die Anfertigung einer Kopie scheint eine Verschwendung von Ressourcen zu sein.

4 Stimmen

@Antzi Das hängt von der Größe der Liste und der Dichte der darin enthaltenen Objekte ab. Dennoch eine wertvolle und gültige Lösung.

0 Stimmen

Ich habe diese Methode angewandt. Sie erfordert etwas mehr Ressourcen, ist aber viel flexibler und klarer.

12voto

Donald Raab Punkte 6053

Mit Eclipse-Kollektionen die Methode removeIf festgelegt am MutableCollection wird funktionieren:

MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.lessThan(3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);

Mit der Java 8 Lambda-Syntax kann dies wie folgt geschrieben werden:

MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.cast(integer -> integer < 3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);

Die Aufforderung an Predicates.cast() ist hier notwendig, weil ein Standard removeIf Methode wurde hinzugefügt auf der java.util.Collection Schnittstelle in Java 8.

Anmerkung: Ich bin ein Beauftragter für Eclipse-Kollektionen .

10voto

from56 Punkte 3695

Mit einer traditionellen for-Schleife

ArrayList<String> myArray = new ArrayList<>();

for (int i = 0; i < myArray.size(); ) {
    String text = myArray.get(i);
    if (someCondition(text))
        myArray.remove(i);
    else
        i++;   
}

1 Stimmen

Ah, es ist also wirklich nur die erweitert -for-Schleife, die die Exception auslöst.

0 Stimmen

FWIW - derselbe Code würde auch noch funktionieren, nachdem er so geändert wurde, dass er inkrementiert wird i++ im Schleifenschutz und nicht im Schleifenkörper.

0 Stimmen

Berichtigung ^: Das heißt, wenn die i++ Die Inkrementierung war nicht bedingt - ich verstehe jetzt, warum man es im Körper macht :)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X