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 addAllam Ende eine Methode ausgeben .
ListIterator verwenden
Wenn Sie mit Listen arbeiten, besteht eine andere Technik darin, eine zu verwenden, ListIteratordie 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 addMethode 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 removeIfMethode in der CollectionBasisklasse 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 removeAllden 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.subSetMethode 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
removeAlTechnik funktionieren mit jeder Sammlung (Sammlung, Liste, Satz usw.).
- Die
ListIteratorTechnik funktioniert offensichtlich nur mit Listen, vorausgesetzt, die angegebene ListIteratorImplementierung bietet Unterstützung für das Hinzufügen und Entfernen von Vorgängen.
- Der
IteratorAnsatz 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
removeAllAnnä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
IteratorSchnittstelle in Javadocs als "optional" markiert ist, was bedeutet, dass es IteratorImplementierungen geben kann, die ausgelöst werden, UnsupportedOperationExceptionwenn 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.