繁体   English   中英

我可以按顺序使用多个 listIterator 来改变或删除 Java 中的 ArrayList 中的列表元素吗?

[英]Can I use many listIterators sequentially to mutate or remove list elements from an ArrayList in Java?

我依靠列表迭代器在字符列表中移动。 这是一个单线程程序,我以 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 文档

这在ArrayList javadoc 中有解释,您在使用Iterator时使用remove()set()修改列表:

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

当显示的代码显然不是产生异常的代码时,很难对问题进行诊断,因为它甚至无法编译。 Iteratorremove方法不采用 arguments 并且set方法在ListIterator上定义,但是您的代码仅将变量i声明为Iterator

固定版本

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

我对 Java ListIterators 不够了解来回答这个问题,但似乎我在这里遇到了 XY 问题。 The problem seems to be better solved with Java Streams to remove the element or map the element into a new ArrayList by exercising a function on each element in the original 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;
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM