【问题标题】:Removing elements while iterating. removeIf result in ConcurrentModificationException迭代时移除元素。 removeIf 导致 ConcurrentModificationException
【发布时间】:2020-02-13 05:45:53
【问题描述】:

我正在尝试从集合 (someObjectSet) 中删除元素,同时循环遍历它。 正如我用谷歌搜索的那样,在这种情况下使用 removeIf 应该避免 ConcurrentModificationException 。 但是这对我不起作用。

谷歌是否对我撒谎(或者我误解了它),或者我没有正确使用 removeIf?

Set<SomeObject> someObjectSet = new HashSet<>();
someObjectSet.add(obj1);
someObjectSet.add(obj2);
someObjectSet.add(obj3);

for (SomeObject obj : someObjectSet ){
    ...
    someObjectSet.removeIf(ele -> if ele satisfies some condition)
}

我想在循环内执行 removeif 的原因是,在每个循环中,可以确定该集合的其他一些元素不再需要进入循环,因此我将其删除以便 for循环不会再次拾取它们。

例如,
在 loop1 中,obj1 被选中。
然后在同一个循环中发现 obj2 不再需要处理 => 从集合中删除 obj2
在loop2中,而不是obj2obj3被拾取

提前致谢!

【问题讨论】:

    标签: java collections


    【解决方案1】:

    不要迭代和removeIf 使用迭代的元素。除了您现在遇到的问题之外,这些调用相当于为集合的每个元素迭代整个集合(因此您在迭代时仍然从集合中删除,这解释了异常!)。

    removeIf 为你迭代,所以你只需要一个 SomeObject 的谓词:

    //no loop
    someObjectSet.removeIf(ele -> if ele satisfies some condition);
    

    其中ele -&gt; if ele satisfies some condition每个SomeObject 元素都将被测试的条件(通过测试的元素将被删除)。 forEach 将在someObjectSet 中的所有元素上编排测试,您不需要这样做。


    如果您有一个要删除元素的次要条件,那么您可以编写谓词(使用or),如下例所示:

    Set<Integer> set = new HashSet<>(Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9));
    
    Predicate<Integer> predicate = s -> s % 2 == 0;
    Predicate<Integer> predicate2 = predicate.or(s -> s % 3 == 0);
    set.removeIf(predicate2);
    
    // Test with set.removeIf(predicate);
    // then with set.removeIf(predicate2);
    // and compare results
    

    【讨论】:

    • 谢谢@ernest_k。我想在循环内执行 removeif 的原因是,在每个循环中,可以确定该集合的其他一些元素不再需要进入循环,因此我将其删除以便 for 循环不会不要再接他们了。我必须为此目的使用迭代器吗?
    • 我明白了。是不是你传递给removeIf 的 lambda 表达式不能同时涵盖这两个条件?这可能是一个有趣的问题,所以请添加一个简单的例子......
    • 我明白你的意思欧内斯特。我认为更直接和更简单的解决方案是维护另一个 toSkipSet,然后在每个循环中,如果 obj 在 toSkipSet 中,则跳过。在这种情况下,即使迭代器也无济于事?
    • @wayne 这通常是在迭代时修改集合的好选择,它应该可以工作。此答案假设您想使用removeIf。 Iterator 将能够实现它,但在我看来,您基于 toSkipSet 的解决方案显然会更好、更简单。
    • @wayne 为了节省外部迭代中的一些工作,您在所有元素上使用了removeIf ,包括您已经处理过的那些......解决方案不是维护要跳过的元素越来越多,但要处理的元素队列:Queue&lt;SomeObject&gt; queue = new ArrayDeque&lt;&gt;(someObjectSet); while(!queue.isEmpty()) { SomeObject obj = queue.remove(); /* ... */ queue.removeIf(ele -&gt; /*if ele satisfies some condition*/); }
    猜你喜欢
    • 2019-09-11
    • 2019-12-11
    • 2013-08-29
    • 2018-05-09
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多