清除子列表时出现ConcurrentModificationException

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

 ArrayList masterList = new ArrayList(); List 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?? 

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

从SubList的源代码中可以看出,方法checkForComodification检查底层列表是否已被修改,因此如果modCount (列表已被结构修改的次数) SubList值与父ArrayList ,然后,它抛出ConcurrentModificationException

因此,清除创建SubListArrayList会导致SubList的某些操作导致ConcurrentModificationException

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

  • 如果删除masterlist's元素,则sublist不存在//exception情况
  • 如果删除sublist's元素,则可以存在masterlist // OK

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

来自API文档 :

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

未定义的语义当然意味着它允许抛出exception(事实上这可能是最明智的行动)。

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