为什么列表的反向子列表的List.addAll导致ConcurrentModificationException

Jol*_*onB 16 java collections arraylist concurrentmodification

我一直在尝试获取列表子列表,将其反转,然后将反转的列表放回起始位置。例如,假设我们拥有列表[1, 2, 3, 4, 5, 6],然后从索引2反转到索引4将得到[1, 2, 5, 4, 3, 6]

我为此编写了一些代码,但是ConcurrentModificationException每次都给出一个代码(除非startIndex == endIndex)。下面提供了一个最小的可重现示例:

int startIndex = 2;
int endIndex = 4;
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);

List<Integer> toReverse = list.subList(startIndex, endIndex+1);
Collections.reverse(toReverse);
list.removeAll(toReverse);
list.addAll(startIndex, toReverse);
Run Code Online (Sandbox Code Playgroud)

异常线程“main” java.util.ConcurrentModificationException
在java.util.ArrayList中的$ SubList.checkForComodification(来源不明)
在java.util.ArrayList的$ SubList.size(来源不明)在
java.util.AbstractCollection.toArray(来源不明)在 test.ConcurrentExample.main(ConcurrentExample.java:64)处
java.util.ArrayList.addAll(Unknown Source

错误所指的实际行是list.addAll(startIndex, toReverse);

我不确定是什么问题,因为迭代过程中似乎没有任何变化。如果有人能解释为什么会这样和/或如何解决它,将不胜感激。

hel*_*ark 11

List.subList返回指定元素之间的列表的实时视图,而不是这些元素的副本(请参阅文档),因此添加到原始列表还将修改子列表,这将导致ConcurrentModificationException(因为要添加的内容和您添加的内容也会同时被修改)。

list.subList(startIndex, endIndex+1)
Run Code Online (Sandbox Code Playgroud)

您可以通过复制列表来修复代码,例如

List<Integer> toReverse = new ArrayList<>(list.subList(startIndex, endIndex+1));
Run Code Online (Sandbox Code Playgroud)


Nir*_*evy 5

ArrayList.subList的文档中:

返回列表受此列表支持,因此返回列表中的非结构性更改会反映在此列表中,反之亦然

因此,当您尝试在子列表“视图”的索引处添加项目时,它将创建并发修改。