Pozwól mi podać kilka przykładów z kilkoma alternatywami, aby uniknąć ConcurrentModificationException .
Załóżmy, że mamy następujący zbiór książek
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")));
Zbieraj i usuwaj
Pierwsza technika polega na zebraniu wszystkich obiektów, które chcemy usunąć (np. Za pomocą rozszerzonej pętli for), a po zakończeniu iteracji usuwamy wszystkie znalezione obiekty.
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);
Zakłada się, że operacja, którą chcesz wykonać, to „usuń”.
Jeśli chcesz „dodać”, to podejście również by działało, ale zakładam, że iterowałbyś inną kolekcję, aby określić, które elementy chcesz dodać do drugiej kolekcji, a następnie wydać addAllmetodę na końcu.
Korzystanie z ListIterator
Jeśli pracujesz z listami, inna technika polega na użyciu narzędzia, ListIteratorktóre obsługuje usuwanie i dodawanie elementów podczas samej iteracji.
ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
if(iter.next().getIsbn().equals(isbn)){
iter.remove();
}
}
Ponownie użyłem metody „usuń” w powyższym przykładzie, co wydaje się sugerować twoje pytanie, ale możesz również użyć jej addmetody, aby dodać nowe elementy podczas iteracji.
Używanie JDK> = 8
Osoby pracujące z wersją Java 8 lub wyższą mogą skorzystać z kilku innych technik, aby z niej skorzystać.
Możesz użyć nowej removeIfmetody w Collectionklasie podstawowej:
ISBN other = new ISBN("0-201-63361-2");
books.removeIf(b -> b.getIsbn().equals(other));
Lub użyj nowego interfejsu API strumienia:
ISBN other = new ISBN("0-201-63361-2");
List<Book> filtered = books.stream()
.filter(b -> b.getIsbn().equals(other))
.collect(Collectors.toList());
W tym ostatnim przypadku, aby odfiltrować elementy z kolekcji, należy ponownie przypisać oryginalne odwołanie do przefiltrowanej kolekcji (tj. books = filtered) Lub użyć przefiltrowanej kolekcji do removeAllznalezionych elementów z oryginalnej kolekcji (tj books.removeAll(filtered).).
Użyj listy podrzędnej lub podzbioru
Istnieją również inne alternatywy. Jeśli lista jest posortowana, a chcesz usunąć kolejne elementy, możesz utworzyć listę podrzędną, a następnie ją wyczyścić:
books.subList(0,5).clear();
Ponieważ lista podrzędna jest poparta oryginalną listą, byłby to skuteczny sposób na usunięcie tego podkolekcji elementów.
Coś podobnego można osiągnąć za pomocą posortowanych zestawów przy użyciu NavigableSet.subSetmetody lub dowolnej dostępnej tam metody krojenia.
Uwagi:
Wybór metody może zależeć od tego, co zamierzasz zrobić
- Odbierz i
removeAlTechnika technika działa z dowolną kolekcją (kolekcja, lista, zestaw itp.).
- Ta
ListIteratortechnika oczywiście działa tylko z listami, pod warunkiem, że ich ListIteratorimplementacja oferuje obsługę operacji dodawania i usuwania.
- The
IteratorPodejście będzie działać z każdym rodzajem kolekcji, ale obsługuje tylko operacje usunięcia.
- Z
ListIterator/Iterator podejściu oczywistą zaletą jest to, że nie trzeba niczego kopiować, ponieważ usuwamy je podczas iteracji. Jest to więc bardzo wydajne.
- Przykład strumieni JDK 8 tak naprawdę niczego nie usunął, ale szukał pożądanych elementów, a następnie zastąpiliśmy oryginalne odwołanie do kolekcji nowym, i pozwoliliśmy, aby stary został wyrzucony. Tak więc powtarzamy tylko raz kolekcję i byłoby to skuteczne.
- W kolekcji i
removeAll podejścia wadą jest to, że musimy iterować dwa razy. Najpierw iterujemy w pętli foor w poszukiwaniu obiektu, który spełnia nasze kryteria usuwania, a gdy go znajdziemy, prosimy o usunięcie go z oryginalnej kolekcji, co oznaczałoby drugą pracę iteracji w celu wyszukania tego elementu w celu usunąć to.
- Myślę, że warto wspomnieć, że metoda remove
Iteratorinterfejsu jest oznaczona jako „opcjonalna” w Javadocs, co oznacza, że mogą istnieć Iteratorimplementacje, które rzucają, UnsupportedOperationExceptionjeśli wywołamy metodę remove. Jako taki, powiedziałbym, że to podejście jest mniej bezpieczne niż inne, jeśli nie możemy zagwarantować iteratora wsparcia dla usuwania elementów.