7

为什么以下代码会抛出ConcurrentModificationExcrption,当我在主列表之后清除子列表时,但如果我清除子列表然后主列表则不会?

ArrayList<Integer> masterList = new ArrayList<Integer>();
List<Integer> subList;

// Add some values to the masterList
for (int i = 0; i < 10; i++) {
    masterList.add(i * i);
}

// Extract a subList from the masterList
subList = masterList.subList(5, masterList.size() - 1);

// The below throws ConcurrentModificationException
masterList.clear();
subList.clear(); // Exception thrown in this line

// The below doesn't throw any exception
subList.clear();
masterList.clear(); // No exception thrown. Confused??
4

4 回答 4

4

SubList不是一个独立的实体,但它只是给出原始列表的视图,并在内部引用相同的列表。因此,它的设计似乎是,如果基础列表在结构上被修改(添加/删除元素),它就无法履行其合同。

正如在 SubList 的源代码中可以看到的,该方法checkForComodification检查底层列表是否已被修改,因此如果modCount(列表已被结构修改的次数)值SubList与 parent 不同ArrayList,则抛出ConcurrentModificationException

ArrayList因此,清除创建的父SubList级可能会导致某些操作SubList导致 ConcurrentModificationException

于 2013-07-27T16:20:49.543 回答
2

subList是一个视图masterList。只有 1 个基础集合。现在 masterList 是一种superset子列表。所以,

  • sublistmasterlist's如果元素被移除则不能存在//异常情况
  • masterlist如果sublist's元素被移除可以存在 //OK
于 2013-07-27T16:05:51.827 回答
2

根据ArrayList doc subList()返回一个由原始 ArrayList 支持的子列表,因此如果原始更改,子列表也会发生变化,当您执行 subList.clear() 时,子列表本身不再存在。

于 2013-07-27T16:07:03.080 回答
2

API 文档

如果后备列表(即此列表)以除通过返回列表之外的任何方式进行结构修改,则此方法返回的列表的语义将变为未定义。(结构修改是改变这个列表的大小,或者以其他方式扰乱它,使得正在进行的迭代可能会产生不正确的结果。)

未定义的语义当然意味着允许抛出异常(实际上这可能是最明智的做法)。

因此,您可以更改子列表的大小并将这些更改反映在主列表中,但反之则不然。

于 2013-07-27T16:07:27.673 回答