为了账号安全,请及时绑定邮箱和手机立即绑定

我可以顺序使用许多 listIterators 来改变或删除 Java 中 ArrayList

我可以顺序使用许多 listIterators 来改变或删除 Java 中 ArrayList

慕哥9229398 2024-01-25 23:04:23
我依靠列表迭代器来移动字符列表。这是一个单线程程序,我在 4 种不同的方法中顺序使用 listIterator 对象。每种方法都有相同的设置: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); // because its lucky    }}使用此模式,在第二个迭代器上将引发以下异常:java.util.ConcurrentModificationException但是,查看 javadocs,我在抛出的异常中没有看到此异常,也没有看到完成后关闭迭代器的方法。我是否错误地使用了 listIterator?我必须多次迭代同一个 ArrayList,每次都有条件地删除或改变每个元素。也许有更好的方法来迭代 ArrayList,而 ListIterator 不能最好地解决这个用例。ListIterator 的 java 文档
查看完整描述

3 回答

?
ibeautiful

TA贡献1993条经验 获得超5个赞

javadoc中对此进行了解释ArrayList,您正在使用以下命令remove()修改列表:set()Iterator

此类的iteratorlistIterator方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间对列表进行结构修改,除了通过迭代器自己的删除或添加方法之外的任何方式,迭代器将抛出ConcurrentModificationException. 因此,面对并发修改,迭代器会快速而干净地失败,而不是在未来不确定的时间冒任意、非确定性行为的风险。



查看完整回答
反对 回复 2024-01-25
?
慕雪6442864

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,因此您的实际问题在其他地方,并且可能仍然存在,无论如何实现这一方法。


查看完整回答
反对 回复 2024-01-25
?
动漫人物

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;

    }


查看完整回答
反对 回复 2024-01-25
  • 3 回答
  • 0 关注
  • 44 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信