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.

1voto

pedram bashiri Punkte 1106

Ich weiß, dass diese Frage zu alt ist, um sich auf Java 8 zu beziehen, aber für diejenigen, die Java 8 verwenden, können Sie einfach removeIf() verwenden:

Collection<Integer> l = new ArrayList<Integer>();

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

l.removeIf(i -> i.intValue() == 5);

1voto

yoAlex5 Punkte 20661

Java Concurrent Modification Exception

  1. Einzelner Faden

    Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String value = iter.next() if (value == "A") { list.remove(it.next()); //throws ConcurrentModificationException } }

Lösung: Iterator remove() Methode

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String value = iter.next()
    if (value == "A") {
        it.remove()
    }
}
  1. Mehrere Fäden
  • Kopieren/Konvertieren und Iterieren über eine andere Sammlung. Für kleine Sammlungen
  • synchronize [Über]
  • fadensichere Sammlung [Über]

0 Stimmen

Eine verkürzte, aber umfassendere Antwort.

0 Stimmen

Ihr erstes Beispiel ist nicht gleichwertig mit Ihrem zweiten oder dem Code des Auftraggebers.

0voto

for (Integer i : l)
{
    if (i.intValue() == 5){
            itemsToRemove.add(i);
            break;
    }
}

Der Haken an der Sache ist, dass nach dem Entfernen des Elements aus der Liste der interne Aufruf von iterator.next() übersprungen wird und trotzdem funktioniert! Auch wenn ich nicht vorschlage, Code wie diesen zu schreiben, hilft es, das Konzept dahinter zu verstehen :-)

Zum Wohl!

0voto

Nandhan Thiravia Punkte 350

Ich habe einen Vorschlag für das oben beschriebene Problem. Sie brauchen keine zweite Liste oder zusätzliche Zeit. Bitte finden Sie ein Beispiel, das dasselbe tut, aber auf eine andere Weise.

//"list" is ArrayList<Object>
//"state" is some boolean variable, which when set to true, Object will be removed from the list
int index = 0;
while(index < list.size()) {
    Object r = list.get(index);
    if( state ) {
        list.remove(index);
        index = 0;
        continue;
    }
    index += 1;
}

Dadurch wird die Concurrency Exception vermieden.

2 Stimmen

In der Frage wird ausdrücklich darauf hingewiesen, dass der OP nicht erforderlich ist, um ArrayList und kann sich daher nicht auf get() . Ansonsten aber wahrscheinlich ein guter Ansatz.

0 Stimmen

(Klarstellung ^) OP verwendet ein beliebiges Collection - Collection Schnittstelle umfasst nicht get . (Obwohl FWIW List Schnittstelle enthält 'get').

0 Stimmen

Ich habe hier eine separate, ausführlichere Antwort auch für while -Looping a List . Aber +1 für diese Antwort, weil sie zuerst kam.

0voto

jagdish khetre Punkte 1111

Die beste Methode (empfohlen) ist die Verwendung von java.util.concurrent Paket. Durch Verwendung dieses Pakets können Sie diese Ausnahme leicht vermeiden. Siehe Geänderter Code:

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

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

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

    System.out.println(l);
}

0 Stimmen

Haben Sie die Leistungseinbußen bedacht? Jedes Mal, wenn Sie in diese Struktur "schreiben", wird ihr Inhalt in ein neues Objekt kopiert. All dies ist schlecht für die Leistung.

0 Stimmen

Das ist nicht der beste Weg und wird nicht empfohlen. Verwenden Sie die Zitatformatierung nicht für Text, der nicht zitiert wird. Wenn der Text zitiert wird, geben Sie eine Quellenangabe an.

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