迭代器在添加元素时如何抛出ConcurrentModificationException?

5

当我们在当前节点之后添加或删除某些对象时,Iterator 如何抛出 ConcurrentModificationException异常?Iterator 是否维护对底层集合的副本或引用?

5个回答

5
迭代器维护对底层集合的引用。如果添加或删除元素,则迭代器可能会留在不可能的索引处,或者集合可能会在迭代器“底下”发生更改。
因此,大多数集合在迭代时尝试修改集合时都会抛出ConcurrentModificationException,而不是让迭代器无法正常工作而你却不知情,这样你就不会得到不可预测的损坏迭代器。

2

根据契约,您在迭代集合时不允许修改它(除非使用 Iterator.remove() 等方法)。

如果您这样做,集合不会随意失败,而是会很好地跟踪修改次数,并在检测到并发修改时抛出 ConcurrentModificationException


1

要进行删除操作,您可以使用迭代器的remove()方法,如下所示:

for (Iterator iterator = list.iterator(); iterator.hasNext();) {
Object object = iterator.next();
    /* ... */
    if (condition) {
       iterator.remove();
    }

对于添加操作,您可以将简单的Iterator替换为ListIterator,如下所示

ListIterator<Object> iterator = list.listIterator();
iterator.add(new Object());

迭代器没有add方法,它仅有三个方法:next、hasNext和remove。 - banjara
你应该使用ListIterator而不仅仅是Iterator类型。 - Moesio

1

那个ConcurrentModificationException可能是你的朋友,你应该学会与它共处。然而,为了完整起见:

有一些非Oracle集合不会抛出ConcurrentModificationException。它们更快(因为它们不花时间检查),显然更灵活,但在使用时需要更加小心。

Oracle有四个(至少)“Concurrent”类,它们不会在java.util.concurrent中抛出异常(ConcurrentHashMap、ConcurrentLinkedQueue、ConcurrentSkipListMap和ConcurrentSkipListSet)。它们比其非并发等效类略慢,但它们是线程安全的,并且它们不会阻塞。无论你做什么,它们都不会破坏你的数据,但它们也不会阻止你破坏它。


0
当然,迭代器有一个指向底层集合的链接,这避免了复制。如果您查看ArrayList迭代器(ListItr)的源代码,例如,您将看到它主要具有与列表和光标的链接。
因此,请勿在线程之间共享迭代器,也不要修改正在迭代的集合。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接