Lassen Sie mich einige Beispiele mit Alternativen nennen, um a zu vermeiden ConcurrentModificationException
.
Angenommen, wir haben die folgende Büchersammlung
List<Book> books = new ArrayList<Book>();
books.add(new Book(new ISBN("0-201-63361-2")));
books.add(new Book(new ISBN("0-201-63361-3")));
books.add(new Book(new ISBN("0-201-63361-4")));
Sammeln und entfernen
Die erste Technik besteht darin, alle Objekte zu sammeln, die wir löschen möchten (z. B. mithilfe einer erweiterten for-Schleife), und nach Abschluss der Iteration alle gefundenen Objekte zu entfernen.
ISBN isbn = new ISBN("0-201-63361-2");
List<Book> found = new ArrayList<Book>();
for(Book book : books){
if(book.getIsbn().equals(isbn)){
found.add(book);
}
}
books.removeAll(found);
Dies setzt voraus, dass der Vorgang, den Sie ausführen möchten, "Löschen" ist.
Wenn Sie diesen Ansatz "hinzufügen" möchten, funktioniert er auch. Ich gehe jedoch davon aus, dass Sie eine andere Sammlung durchlaufen, um zu bestimmen, welche Elemente Sie einer zweiten Sammlung hinzufügen möchten, und addAll
am Ende eine Methode ausgeben .
ListIterator verwenden
Wenn Sie mit Listen arbeiten, besteht eine andere Technik darin, eine zu verwenden, ListIterator
die das Entfernen und Hinzufügen von Elementen während der Iteration selbst unterstützt.
ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
if(iter.next().getIsbn().equals(isbn)){
iter.remove();
}
}
Auch hier habe ich im obigen Beispiel die Methode "Entfernen" verwendet, was Ihre Frage zu implizieren schien. Sie können jedoch auch die add
Methode verwenden, um während der Iteration neue Elemente hinzuzufügen.
Verwenden von JDK> = 8
Für diejenigen, die mit Java 8 oder höheren Versionen arbeiten, gibt es einige andere Techniken, die Sie verwenden können, um davon zu profitieren.
Sie können die neue removeIf
Methode in der Collection
Basisklasse verwenden:
ISBN other = new ISBN("0-201-63361-2");
books.removeIf(b -> b.getIsbn().equals(other));
Oder verwenden Sie die neue Stream-API:
ISBN other = new ISBN("0-201-63361-2");
List<Book> filtered = books.stream()
.filter(b -> b.getIsbn().equals(other))
.collect(Collectors.toList());
In diesem letzten Fall weisen Sie zum Filtern von Elementen aus einer Sammlung den ursprünglichen Verweis der gefilterten Sammlung (dh books = filtered
) neu zu oder verwenden die gefilterte Sammlung removeAll
den gefundenen Elementen aus der ursprünglichen Sammlung (dh books.removeAll(filtered)
).
Verwenden Sie Unterliste oder Teilmenge
Es gibt auch andere Alternativen. Wenn die Liste sortiert ist und Sie aufeinanderfolgende Elemente entfernen möchten, können Sie eine Unterliste erstellen und diese dann löschen:
books.subList(0,5).clear();
Da die Unterliste durch die ursprüngliche Liste unterstützt wird, wäre dies eine effiziente Möglichkeit, diese Unterkollektion von Elementen zu entfernen.
Ähnliches könnte mit sortierten Sätzen unter Verwendung der NavigableSet.subSet
Methode oder einer der dort angebotenen Schneidemethoden erreicht werden.
Überlegungen:
Welche Methode Sie verwenden, hängt möglicherweise davon ab, was Sie vorhaben
- Das Sammeln und die
removeAl
Technik funktionieren mit jeder Sammlung (Sammlung, Liste, Satz usw.).
- Die
ListIterator
Technik funktioniert offensichtlich nur mit Listen, vorausgesetzt, die angegebene ListIterator
Implementierung bietet Unterstützung für das Hinzufügen und Entfernen von Vorgängen.
- Der
Iterator
Ansatz funktioniert mit jeder Art von Sammlung, unterstützt jedoch nur Entfernungsvorgänge.
- Mit dem
ListIterator
/ Iterator
-Ansatz besteht der offensichtliche Vorteil darin, dass nichts kopiert werden muss, da wir es beim Iterieren entfernen. Das ist also sehr effizient.
- Das Beispiel für JDK 8-Streams hat eigentlich nichts entfernt, sondern nach den gewünschten Elementen gesucht. Dann haben wir die ursprüngliche Sammlungsreferenz durch die neue ersetzt und die alte als Müllsammlung verwendet. Wir iterieren also nur einmal über die Sammlung, und das wäre effizient.
- Beim Sammeln und
removeAll
Annähern besteht der Nachteil darin, dass wir zweimal iterieren müssen. Zuerst iterieren wir in der Foor-Schleife nach einem Objekt, das unseren Entfernungskriterien entspricht, und sobald wir es gefunden haben, bitten wir Sie, es aus der ursprünglichen Sammlung zu entfernen, was eine zweite Iterationsarbeit bedeuten würde, um nach diesem Element zu suchen entfernen Sie es.
- Ich denke, es ist erwähnenswert, dass die Methode remove der
Iterator
Schnittstelle in Javadocs als "optional" markiert ist, was bedeutet, dass es Iterator
Implementierungen geben kann, die ausgelöst werden, UnsupportedOperationException
wenn wir die Methode remove aufrufen. Daher würde ich sagen, dass dieser Ansatz weniger sicher ist als andere, wenn wir die Iterator-Unterstützung für das Entfernen von Elementen nicht garantieren können.