Bir kaçınmak için bazı alternatiflerle birkaç örnek vereyim ConcurrentModificationException.
Aşağıdaki kitap koleksiyonuna sahip olduğumuzu varsayalım
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")));
Topla ve Kaldır
İlk teknik, silmek istediğimiz tüm nesneleri (örn. Döngü için gelişmiş bir kullanarak) toplamaktır ve yinelemeyi bitirdikten sonra bulunan tüm nesneleri kaldırırız.
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);
Bu, yapmak istediğiniz işlemin "sil" olduğunu varsayar.
"Eklemek" istiyorsanız bu yaklaşım da işe yarayacaktır, ancak ikinci bir koleksiyona hangi öğeleri eklemek istediğinizi belirlemek için farklı bir koleksiyon üzerinde yineleme yapacağınızı addAllve sonunda bir yöntem yayınlayacağınızı varsayarım .
ListIterator'ı kullanma
Listelerle çalışıyorsanız, başka bir teknik ListIterator, yinelemenin kendisi sırasında öğelerin kaldırılması ve eklenmesi için destek olan bir yöntemi kullanmaktan oluşur .
ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
if(iter.next().getIsbn().equals(isbn)){
iter.remove();
}
}
Yine, yukarıdaki örnekte sorunuzun ima ettiği gibi görünen "kaldır" yöntemini kullandım, ancak addyöntemini yineleme sırasında yeni öğeler eklemek için de kullanabilirsiniz .
JDK kullanma> = 8
Java 8 veya üstün sürümlerle çalışanlar için, bundan yararlanmak için kullanabileceğiniz birkaç teknik daha vardır.
Temel sınıftaki yeni removeIfyöntemi kullanabilirsiniz Collection:
ISBN other = new ISBN("0-201-63361-2");
books.removeIf(b -> b.getIsbn().equals(other));
Veya yeni akış API'sını kullanın:
ISBN other = new ISBN("0-201-63361-2");
List<Book> filtered = books.stream()
.filter(b -> b.getIsbn().equals(other))
.collect(Collectors.toList());
Bu son durumda, öğeleri bir koleksiyondan filtrelemek için, orijinal referansı filtrelenmiş koleksiyona yeniden atayabilirsiniz (yani books = filtered) veya filtrelenmiş koleksiyonu removeAllorijinal koleksiyondaki (yani books.removeAll(filtered)) bulunan öğelere yeniden kullanırsınız .
Alt Liste veya Altküme Kullan
Başka alternatifler de var. Liste sıralıysa ve art arda gelen öğeleri kaldırmak istiyorsanız bir alt liste oluşturabilir ve listeyi temizleyebilirsiniz:
books.subList(0,5).clear();
Alt liste orijinal liste ile desteklendiğinden, bu, öğelerin bu alt toplanmasını kaldırmanın etkili bir yolu olacaktır.
Benzer bir şey NavigableSet.subSetyöntemi kullanarak sıralı kümelerle veya orada sunulan dilimleme yöntemlerinden herhangi biri ile elde edilebilir .
hususlar:
Hangi yöntemi kullandığınız, ne yapmak istediğinize bağlı olabilir
removeAlKoleksiyon ve teknik herhangi bir Koleksiyon (Koleksiyon, Liste, Set, vb.) İle çalışır.
ListIteratorTeknik, açıkça, kendilerine verilen şartıyla listeleri ile çalışır ListIteratoruygulama teklifler eklemek ve kaldırmak işlemleri için destekler.
IteratorYaklaşım koleksiyonun her türlü ile çalışacak, ama bu kaldırma işlemlerini destekleyen tek.
- İle
ListIterator/ Iteratorbariz avantajı biz yineleme olarak kaldırmak beri hiçbir şey kopyalamak zorunda değildir yaklaşır. Yani, bu çok verimli.
- JDK 8 akış örneği aslında hiçbir şeyi kaldırmadı, ancak istenen öğeleri aradık ve orijinal koleksiyon referansını yenisiyle değiştirdik ve eskisinin çöp toplanmasına izin verdik. Yani, koleksiyon üzerinde sadece bir kez tekrarlıyoruz ve bu verimli olacaktır.
- Toplama ve
removeAllyaklaşımda dezavantaj iki kez yinelememiz gerektiğidir. İlk olarak, foop-döngüsünde kaldırma ölçütlerimizle eşleşen bir nesneyi ararız ve onu bulduktan sonra, orijinal koleksiyondan kaldırmayı isteriz, bu da bu öğeyi aramak için ikinci bir yineleme çalışması anlamına gelir. onu kaldır.
IteratorArayüz kaldırma yönteminin Javadocs'ta "isteğe bağlı" olarak işaretlendiğinden bahsetmeye değer olduğunu düşünüyorum, bu da kaldırma yöntemini çağırdığımızda Iteratoratılan uygulamalar olabileceği anlamına gelir UnsupportedOperationException. Bu nedenle, elemanların kaldırılması için yineleyici desteğini garanti edemezsek, bu yaklaşımın diğerlerinden daha az güvenli olduğunu söyleyebilirim.