当前位置: 首页 > 面试题库 >

为什么iterator.remove不引发ConcurrentModificationException

关宏毅
2023-03-14
问题内容

有什么iterator.remove()不同之处与list.remove()使得迭代器不会引发异常而list.remove()引发异常?最后,两者都在修改集合大小。

请在这里忽略多线程。我只是在谈论一个for-each循环和一个迭代器循环。据我所知,for-each循环仅在内部创建迭代器。

我很困惑。


问题答案:

ConcurrentModificationException不会抛出,Iterator.remove()因为这是在迭代时修改集合的 允许
方式。这是什么的Javadoc的Iterator说:

从基础集合中移除此迭代器返回的最后一个元素(可选操作)。每次调用next()只能调用一次此方法。
如果在迭代进行过程中以其他方式(而不是通过调用此方法)修改了基础集合,则未指定迭代器的行为。

如果以任何其他方式更改要迭代的集合,则有可能会获得异常,具体取决于迭代器的实现以及要迭代的集合(或其他任何东西)。(某些集合类不会给您一个ConcurrentModificationException:检查相应的javadocs,以了解它们如何指定
迭代器的行为)

如果您在同一集合上有两个迭代器,并且通过其中一个进行删除,则您也有可能会获得异常。

iterator.remove与list.remove有什么不同,item在list.remove会抛出异常时不会引发异常?

原因#1。如果您有一个非并发集合在同一调用堆栈的两个位置上同时进行更新,则该行为将破坏迭代1的设计不变性。保证非并发集合的迭代能够准确地看到该集合中的所有元素。(通过对比,并发收集使这些保证放宽了。)

原因2。非并发收集类型未实现为线程安全的。因此,如果使用集合和迭代器通过不同的线程更新集合,则可能会出现竞争状况和内存异常。这不是 很强的
理由,因为无论如何您都会遇到这些问题。但是,以两种不同的方式进行更新会使问题变得更糟。

我只是在谈论for-each循环和迭代器循环。据我所知,for-each循环仅在内部创建迭代器。

那是正确的。for-each循环实际上只是while使用迭代器的循环的语法糖。

另一方面,如果使用这样的循环:

    for (int i = 0; i < list.size(); i++) {
        if (...) {
            list.remove(i);
        }
    }

您不会得到ConcurrentModificationException,但是您将需要为删除的元素调整index变量,并且另一个线程进行的更新可能会导致您跳过元素或多次访问它们2。

1-要实现“恰好一次”的迭代行为,当通过集合对象删除元素时,将需要更新迭代器数据结构,以使其与集合发生的情况保持一致。在当前的实现中,这是不可能的,因为它们不保持与未完成的迭代器的链接。如果这样做的话,他们将需要使用Reference对象或冒内存泄漏的风险。

2-甚至得到一个IndexOutOfBoundsException。而且,如果集合没有并发/没有正确同步,则可能会遇到更严重的问题。



 类似资料:
  • 问题内容: 需要对以下代码进行澄清: 这将打印出来,以便证明和对象引用相同的内存引用。 这将打印出来,也证明是相同的。 显然,这将引发,因为我试图调用空引用。 所以这是我的问题,为什么最后一个代码示例没有抛出,因为我从前两个示例中看到并理解的是,如果两个对象都引用同一个对象,那么如果我们更改任何值,那么它也会反映给另一个对象,因为两个对象都指向相同的内存引用。那么,为什么该规则在这里不适用?如果我

  • 问题内容: 为什么这段代码不抛出?它在不使用方法的情况下修改了一段时间,这是唯一安全的删除方法。 如果将替换为,则会得到相同的结果。但是,如果我将列表更改为或只是得到了预期的异常。到底是怎么回事?我正在使用是否相关。 编辑 我找到了以下链接 http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4902078 相关部分是 天真的解决方案是将协同修改

  • 问题内容: 我通过文档(去http://java.sun.com/javase/6/docs/api/java/util/Iterator.html)的 存在)被描述成 从基础集合中移除迭代器返回的最后一个元素(可选操作)。每次调用next只能调用一次此方法。如果在迭代进行过程中以其他方式(而不是通过调用此方法)修改了基础集合,则未指定迭代器的行为。 因此,任何人都可以说出“可选”的含义。 这会影

  • 问题内容: 我一直在尝试使用解析文件: 当然,这是我的代码的简化版本,但这足以破坏我的程序。如果删除try-catch块,则会出现一些文件出现此错误的情况: 但是,结果是确定性的,如果文件有效,它将始终有效。如果文件失败,则它总是失败并且总是在同一点失败。 最奇怪的是,我正在使用跟踪来确定是否有任何格式错误的XML破坏了解析器。然后,我隔离导致故障的节点。但是,当我创建一个包含该节点及其几个邻居的

  • 问题内容: 为什么这段代码没有抛出?看一看: 我不知道! 问题答案: 您为什么不能自己检查一下并抛出异常(如果您要的话)。