Stack<String> ST = new Stack<String>();
ST.add("one");
ST.add("two");
ST.add("three");
ST.add("four");
ST.addAll(ST.subList(0,2));
System.out.println(ST);
遵循简单代码给j ava.util.ConcurrentModificationException
。我无法弄清楚这个例外背后的原因是什么?
答案 0 :(得分:2)
List.subList
将视图返回到容器中,而不是副本。
如果是,则此方法返回的列表的语义将变为未定义 支持列表(即,该列表)以任何方式在结构上被修改 除了通过返回的列表。 (结构修改是那些 这会改变这个列表的大小,或以其他方式扰乱它 方式,正在进行的迭代可能会产生不正确的结果。)
因此,当您调用addAll时,它会修改基础容器并更改其大小,从而使子列表无效。但它仍在尝试迭代子列表以继续添加内容。
答案 1 :(得分:1)
documentation for the subList
method说:
如果支持列表(即此列表)以除了通过返回的List之外的任何方式进行结构修改,则此方法返回的List的语义将变为未定义。 (结构修改是那些改变列表大小的修改,或以其他方式扰乱它,使得正在进行的迭代可能产生不正确的结果。)
换句话说,当您访问子列表时,您不允许更改真实列表。
致电时
ST.addAll(ST.subList(0,2));
您导致addAll
遍历子列表并同时修改真实列表(ST
)。 addAll
将从子列表中获取第一个元素并将其附加到ST
,这是一种结构修改,可使基于ST
的所有子列表无效。然后addAll
将尝试从子列表中获取第二个元素,但由于刚刚对ST
进行了更改,子列表现在无效,因此它会抛出异常。
答案 2 :(得分:0)
问题发生在这里:
ST.addAll(ST.subList(0,2));
问题在于引发了以下事情:
ST.subList(0,2)
调用会为原始列表创建一个包装器。
ST.addAll
调用为子列表创建Iterator
,该列表实际上是原始列表ListIterator
的包装。
然后,在迭代子列表(以及列表)时,它会将找到的元素推回到原始列表中。
最后一个是并发修改。
请注意,这是固有的,而不仅仅是实现细节。 subList
方法返回原始List
的视图。因此,您的语句本身就是在同时迭代和修改相同的(底层)列表。