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ć addAll
metodę na końcu.
Korzystanie z ListIterator
Jeśli pracujesz z listami, inna technika polega na użyciu narzędzia, ListIterator
któ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 add
metody, 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 removeIf
metody w Collection
klasie 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 removeAll
znalezionych 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.subSet
metody lub dowolnej dostępnej tam metody krojenia.
Uwagi:
Wybór metody może zależeć od tego, co zamierzasz zrobić
- Odbierz i
removeAl
Technika technika działa z dowolną kolekcją (kolekcja, lista, zestaw itp.).
- Ta
ListIterator
technika oczywiście działa tylko z listami, pod warunkiem, że ich ListIterator
implementacja oferuje obsługę operacji dodawania i usuwania.
- The
Iterator
Podejś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
Iterator
interfejsu jest oznaczona jako „opcjonalna” w Javadocs, co oznacza, że mogą istnieć Iterator
implementacje, które rzucają, UnsupportedOperationException
jeś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.