3 回答
TA贡献1993条经验 获得超5个赞
javadoc中对此进行了解释ArrayList
,您正在使用以下命令remove()
修改列表:set()
Iterator
此类的
iterator
和listIterator
方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间对列表进行结构修改,除了通过迭代器自己的删除或添加方法之外的任何方式,迭代器将抛出ConcurrentModificationException
. 因此,面对并发修改,迭代器会快速而干净地失败,而不是在未来不确定的时间冒任意、非确定性行为的风险。
TA贡献1812条经验 获得超5个赞
当显示的代码显然不是产生异常的代码时,很难对问题进行诊断,因为它甚至无法编译。remove的方法不Iterator接受参数,并且该set方法是在 上定义的,但您的代码仅ListIterator将变量声明为。iIterator
固定版本
private void myMethod(ArrayList<Integer> input) {
ListIterator<Integer> i = input.listIterator();
while (i.hasNext()) {
Integer in = i.next();
if (in < 10)
i.remove();
else
i.set(in*in);
}
}
会毫无问题地运行。您的一般问题的答案是,每次修改都会使所有现有迭代器无效,除了当您确实使用迭代器而不是直接使用集合接口进行修改时用于进行修改的迭代器。
但在您的代码中,只有一个迭代器,它仅针对这一操作而创建和使用。只要不重复使用同一个集合的迭代器,就不会出现失效问题。无论如何,先前操作中存在的迭代器都会被放弃,并且后续操作中使用的迭代器还不存在。
尽管如此,它还是更容易使用
private void myMethod(ArrayList<Integer> input) {
input.removeIf(in -> in < 10);
input.replaceAll(in -> in*in);
}
反而。与原始代码不同,这会执行两次迭代,但正如本答案中所解释的,removeIf在性能确实很重要的情况下,实际上会比基于迭代器的删除更快。
但问题仍然存在。显示的代码不会导致ConcurrentModificationException,因此您的实际问题在其他地方,并且可能仍然存在,无论如何实现这一方法。
TA贡献1815条经验 获得超10个赞
我对 Java ListIterators 的了解不够,无法回答这个问题,但看来我在这里遇到了 XY 问题。使用 Java Streams 似乎可以更好地解决这个问题,即通过对原始 ArrayList 中的每个元素执行函数来删除元素或将元素映射到新的 ArrayList 中。
private ArrayList<Integer> myMethod(ArrayList<Integer> input) {
ArrayList<Integer> results = input.stream().filter(
in -> (in < 10)).collect(Collectors.toCollection(ArrayList::new));
results = input.stream().map(
in -> in*in).collect(Collectors.toCollection(ArrayList::new));
return results;
}
添加回答
举报