首页 > 解决方案 > 迭代时移除元素。removeIf 导致 ConcurrentModificationException

问题描述

我试图在循环遍历集合时从集合(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 中,而不是obj2,obj3被拾取

提前致谢!

标签: javacollections

解决方案


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

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

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

每个元素将被测试ele -> if ele satisfies some condition的条件在哪里(通过测试的元素将被删除)。将对中的所有元素编排测试,您不需要这样做。SomeObjectforEachsomeObjectSet


如果您有要删除元素的次要条件,那么您可以组合谓词(使用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

推荐阅读