迭代时从哈希集中删除元素

2022-08-31 08:29:54

因此,如果我在迭代时尝试从Java HashSet中删除元素,我会得到一个ConcurrentModificationException。从 HashSet 中删除元素子集的最佳方法是什么,如以下示例所示?

Set<Integer> set = new HashSet<Integer>();

for(int i = 0; i < 10; i++)
    set.add(i);

// Throws ConcurrentModificationException
for(Integer element : set)
    if(element % 2 == 0)
        set.remove(element);

这是一个解决方案,但我认为它不是很优雅:

Set<Integer> set = new HashSet<Integer>();
Collection<Integer> removeCandidates = new LinkedList<Integer>();

for(int i = 0; i < 10; i++)
    set.add(i);

for(Integer element : set)
    if(element % 2 == 0)
        removeCandidates.add(element);

set.removeAll(removeCandidates);

谢谢!


答案 1

您可以手动循环访问集合的元素:

Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {
    Integer element = iterator.next();
    if (element % 2 == 0) {
        iterator.remove();
    }
}

您经常会看到此模式使用循环而不是循环:forwhile

for (Iterator<Integer> i = set.iterator(); i.hasNext();) {
    Integer element = i.next();
    if (element % 2 == 0) {
        i.remove();
    }
}

正如人们所指出的,使用循环是首选,因为它将迭代器变量(在本例中)限制在较小的范围内。fori


答案 2

您获得的原因是因为通过 Set.remove() 而不是 Iterator.remove() 删除条目。如果在迭代过程中通过 Set.remove() 删除了一个条目,您将获得一个 ConcurrentModificationException。另一方面,在这种情况下,支持在迭代时通过 Iterator.remove() 删除条目。ConcurrentModificationException

新的 for 循环很不错,但不幸的是,它在这种情况下不起作用,因为你不能使用迭代器引用。

如果需要在迭代时删除条目,则需要使用直接使用迭代器的长格式。

for (Iterator<Integer> it = set.iterator(); it.hasNext();) {
    Integer element = it.next();
    if (element % 2 == 0) {
        it.remove();
    }
}