清除子列表时出现ConcurrentModificationException异常

7
当我先清空母列表再清空子列表时,为什么下面的代码会抛出ConcurrentModificationException异常,但是如果我先清空子列表再清空母列表就不会呢?
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

SubList并不是一个独立的实体,而只是原始列表的一种视图,并且内部引用了同一个列表。因此,它的设计似乎是这样的,如果底层列表在结构上发生了修改(添加/删除元素),它就无法履行其合同。

正如可以在此处查看SubList源代码,方法checkForComodification检查底层列表是否已被修改,因此,如果SubListmodCount值(列表结构已经修改的次数)与父ArrayList不同,那么它会抛出ConcurrentModificationException

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


这非常有信息量。谢谢。 - Code.me

2

subListmasterList 的视图。这里只有一个底层集合。现在,masterList 可以看作是 sublist 的超集。所以:

  • 如果移除了 masterlist 的元素,则 sublist 不能存在 //异常情况
  • 如果移除了 sublist 的元素,则 masterlist 可以存在 //OK

subList是指masterList的元素,当我执行masterList.clear()时,引用被销毁,subList.clear()会抛出异常吗? - Code.me

2
根据 ArrayList 文档subList() 方法返回的子列表是由原始 ArrayList 支持的,因此如果原始列表发生更改,则子列表也会发生更改。当您执行 subList.clear() 时,子列表本身将不再存在。

2
API文档中得知:
如果在除返回的列表之外以任何方式(即结构上修改)修改后备列表(即此列表),则此方法返回的列表语义将变得不确定。(结构修改是那些改变此列表大小或以使进行中的迭代可能产生不正确结果的方式扰乱它的修改。)
未定义的语义当然意味着可以抛出异常(实际上这可能是最明智的做法)。
因此,您可以更改子列表的大小,并在主列表中反映这些更改,但反过来则不成立。

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