小編典典
讓我舉幾個例子,并提出一些避免方案ConcurrentModificationException。
假設我們有以下藏書
List books = new ArrayList();
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")));
收集并删除
第一種技術是收集所有要删除的對象(例如,使用增強的for循環),并在完成疊代後删除所有找到的對象。
ISBN isbn = new ISBN("0-201-63361-2");
List found = new ArrayList();
for(Book book : books){
if(book.getIsbn().equals(isbn)){
found.add(book);
}
}
books.removeAll(found);
假設你要執行的操作是“删除”。
如果要“添加”此方法也可以,但是我認為你将周遊另一個集合,以确定要添加到第二個集合中的元素,然後addAll在最後發出一個方法。
使用ListIterator
如果要使用清單,則另一種技術是使用ListIterator,它支援在疊代過程中删除和添加項目。
ListIterator iter = books.listIterator();
while(iter.hasNext()){
if(iter.next().getIsbn().equals(isbn)){
iter.remove();
}
}
同樣,我在上面的示例中使用了“删除”方法,這似乎是你的問題所暗示的含義,但是你也可以add在疊代過程中使用其方法添加新元素。
使用JDK> = 8
對于使用Java 8或更高版本的使用者,你可以使用多種其他技術來利用它。
你可以removeIf在Collection基類中使用新方法:
ISBN other = new ISBN("0-201-63361-2");
books.removeIf(b -> b.getIsbn().equals(other));
或使用新的流API:
ISBN other = new ISBN("0-201-63361-2");
List filtered = books.stream()
.filter(b -> b.getIsbn().equals(other))
.collect(Collectors.toList());
在後一種情況下,要從books = filtered集合中過濾元素,你可以将原始引用重新配置設定給過濾後的集合(即),或将過濾後的集合用于removeAll從原始集合中找到的元素(即books.removeAll(filtered))。
使用子清單或子集
還有其他選擇。如果清單已排序,并且要删除連續的元素,則可以建立一個子清單,然後清除它:
books.subList(0,5).clear();
由于子清單由原始清單支援,是以這将是删除此元素子集合的有效方法。
使用NavigableSet.subSet方法或那裡提供的任何切片方法,可以通過排序集實作類似的效果。
注意事項:
你使用哪種方法可能取決于你打算做什麼
removeAl集合和技術可與任何集合(集合,清單,集合等)一起使用。
該ListIterator技術顯然僅适用于清單,隻要它們的給定ListIterator實作為添加和删除操作提供支援。
該Iterator方法适用于任何類型的集合,但僅支援删除操作。
使用ListIterator/ Iterator方法,明顯的優點是不必複制任何内容,因為我們在疊代時将其删除。是以,這非常有效。
JDK 8流示例實際上并未删除任何内容,而是查找所需的元素,然後我們用新的引用替換了原始的收集引用,并讓舊的引用進行了垃圾收集。是以,我們隻對集合進行一次疊代,這樣會很有效。
在收集和removeAll進行中,缺點是我們必須疊代兩次。首先,我們在foor循環中進行疊代,以尋找一個符合移除條件的對象,一旦找到該對象,便要求将其從原始集合中移除,這意味着需要進行第二次疊代來尋找該對象,以便去掉它。
我認為值得一提的是,該Iterator接口的remove方法在Javadocs中被标記為“可選”,這意味着如果我們調用remove方法,可能會Iterator抛出一些實作UnsupportedOperationException。是以,如果我們不能保證疊代器支援删除元素,那麼這種方法将不如其他方法安全。
2020-03-11