AFAIK,有两种方法:
例如,
List<Foo> fooListCopy = new ArrayList<Foo>(fooList); for(Foo foo : fooListCopy){ // modify actual fooList }
和
Iterator<Foo> itr = fooList.iterator(); while(itr.hasNext()){ // modify actual fooList using itr.remove() }
有什么理由更喜欢一种方法而不是另一种(例如,出于可读性的简单原因更喜欢第一种方法)?
让我举几个例子和一些替代方案来避免ConcurrentModificationException.
ConcurrentModificationException
假设我们有以下书籍集合
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")));
收集和删除
第一种技术包括收集我们想要删除的所有对象(例如,使用增强的 for 循环),在我们完成迭代后,我们删除所有找到的对象。
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);
这是假设您要执行的操作是“删除”。
如果您想“添加”这种方法也可以,但我假设您将遍历不同的集合以确定要添加到第二个集合的元素,然后addAll在最后发出一个方法。
addAll
使用 ListIterator
如果您正在使用列表,另一种技术是使用ListIterator支持在迭代过程中删除和添加项目的 a。
ListIterator
ListIterator<Book> iter = books.listIterator(); while(iter.hasNext()){ if(iter.next().getIsbn().equals(isbn)){ iter.remove(); } }
同样,我在上面的示例中使用了“删除”方法,这似乎是您的问题所暗示的,但您也可以使用它的add方法在迭代期间添加新元素。
add
使用 JDK >= 8
对于那些使用 Java 8 或更高版本的人,您可以使用其他一些技术来利用它。
您可以在基类中使用新removeIf方法:Collection
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<Book> filtered = books.stream() .filter(b -> b.getIsbn().equals(other)) .collect(Collectors.toList());
在最后一种情况下,要从集合中过滤元素,您可以将原始引用重新分配给过滤的集合(ie books = filtered),或者将过滤的集合用于removeAll从原始集合(ie books.removeAll(filtered))中找到的元素。
books = filtered
removeAll
books.removeAll(filtered)
使用子列表或子集
还有其他选择。如果列表已排序,并且您想要删除连续的元素,您可以创建一个子列表,然后将其清除:
books.subList(0,5).clear();
由于子列表由原始列表支持,这将是删除此元素子集合的有效方法。
NavigableSet.subSet使用方法的排序集或那里提供的任何切片方法都可以实现类似的效果。
NavigableSet.subSet
注意事项:
您使用什么方法可能取决于您打算做什么
removeAl
Iterator
UnsupportedOperationException