当前位置: 首页 > 知识库问答 >
问题:

从列表中删除项时的ConcurrentModificationException[重复]

安浩瀚
2023-03-14

我有一个自定义列表类的应用程序。尝试使用customer参数执行foreach函数时,会发生以下情况:

重要!我不能修改主代码

主要内容:

XList<Integer> lmod = XList.of(1,2,8, 10, 11, 30, 3, 4);
lmod.forEachWithIndex( (e, i) -> lmod.set(i, e*2));
System.out.println(lmod);
lmod.forEachWithIndex( (e, i) -> { if (i % 2 == 0) lmod.remove(e); } );
System.out.println(lmod);
lmod.forEachWithIndex( (e, i) -> { if (i % 2 == 0) lmod.remove(i); } );
System.out.println(lmod);

XList类:

public class XList <T> extends ArrayList<T> {
public XList(Collection<T> collection) {
    super(collection);
}

public XList(T... ints) {
    super(Arrays.asList(ints));
}

public static <T> XList<T> of(Set<T> set) {
    return new XList<>(set);
}

public static <T> XList<T> of(T... ints) {
    return new XList<>(ints);
}

public void forEachWithIndex(BiConsumer<? super T, ? super Integer> consumer) {
    Iterator<T> iterator = this.iterator();

    int counter = 0;

    while (iterator.hasNext()) {
        consumer.accept(iterator.next(), counter);
        counter++;
    }
}

错误:

Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
at zad1.XList.forEachWithIndex(XList.java:126)
at zad1.Main.main(Main.java:89)

共有1个答案

吕修筠
2023-03-14

异常是指:

  1. 在时间点A,您可以通过调用某个集合的. iterator()方法,或者使用(var x:集合)的{}调用它。
  2. 在时间点B,您更改集合(而不是通过您在A的中创建的迭代器。移除()方法),例如通过调用移除添加清除retainAll.
  3. 在时间点C,你在迭代器上看起来很有趣:你调用它的任何方法,或者你让for循环通过点击它的块的}来完成它。

你所需要做的绝对是不平凡的!

考虑一下,给定一个[A,B,C,D,E]的初始列表:您可能希望forEachWithIndex方法运行5次,而不管[0,A]、[1,B]、[2,C]、[3,D]和[4,E]之间的列表发生了什么。那么,如果在[0,A]的循环过程中,您删除了C,会发生什么呢?

有一个论点认为[2,C]事件根本不应该发生,事实上,剩下的循环应该是[1,B][2,D][3,E]。这是因为这很难回答,java解决了iterator()API中的问题,只是不允许您这么做!

当您调用时,也会出现类似的问题。在[0,A]的循环过程中添加(“F”)。for循环是否应该使用参数[5,F]运行lambda一次?一个悬而未决的问题。

这取决于你回答这个问题,你应该详细记录这个问题。无论你做什么选择,都会很困难!

这是难以置信的复杂。因为假设C的循环最终删除了A。这意味着您的列表将首先调用λ,其中包含参数[0,A][1,B][2,C],然后下一个迭代会是什么样子?大概唯一理智的答案是[2, D]。为了做到这一点,你需要跟踪各种各样的事情——列表的循环代码需要意识到删除发生了,因此需要“向下调整”(因为你不能简单地从0循环到“列表大小”,如果你这样做了,那么下一个迭代将是[3, E],您已经完全跳过了D,即使它仍然在列表中。

煮些咖啡,挖进去,找块白板,画出草图。预留一整天的时间,并注意代码将有很多页来处理这一切。制作大量的测试用例,并精确地描述所有这些测试用例的预期结果。

这样比较容易,但是效率不高。修复方法很简单:首先复制列表。然后迭代副本。副本不能更改(你是唯一有参考的人),所以他们可以对基础列表做任何他们想做的事情:

XList<T> copy = new XList<T>(this);
int counter = 0;

var iterator = copy.iterator();
while (iterator.hasNext()) consumer.accept(iterator.next(), counter++);
 类似资料:
  • 我有一个自定义列表类的应用程序。当尝试使用customer参数执行foreach函数时,会发生以下情况: 错误:

  • 我试图编辑我的deletar()方法,把一个迭代器移除元素,但没有工作,错误继续。

  • 实际上,在按下一个按钮后,我有一个方法可以检查itemStorico ArrayList中是否存在从itemModel添加的新项,然后如果该项存在于名为itemModel的新列表中,我将从itemStorico中删除旧项并添加新项,否则只添加新项而不删除旧项。 但我得到以下错误: 下面是我的方法中的代码:

  • 问题内容: 我在Python中有一个列表列表: 我想从中删除重复的元素。如果这是正常列表,而不是我可以使用的列表set。但不幸的是,该列表不可散列,因此无法建立一组列表。只有元组。因此,我可以将所有列表转换为元组,然后使用set并返回列表。但这不是很快。 如何以最有效的方式做到这一点? 上面的结果应为: 我不在乎保留订单。 注意:这个问题很相似,但不是我所需要的。搜索了SO,但没有找到确切的重复项

  • 我下面有一个类,想删除包含同名的重复人,如何使用Java8 Lambda,预计列表包含下面的p1、p3。

  • 问题内容: 如果想基于每个嵌套列表的第一个元素评估重复项,谁能提出一个好的解决方案从嵌套列表中删除重复项? 主列表如下所示: 如果已经在第一位置出现了另一个具有相同元素的列表,那么我想删除该列表并得到以下结果: 您可以建议一种算法来实现此目标吗? 问题答案: 您是否关心保留订单/删除了哪些重复项?如果不是,则: 会做的。如果您想保留订单并想保留第一个订单,则: