问题

这个问题在这里已有答案:

  • 迭代集合,在循环22中删除答案时避免ConcurrentModificationException

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

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 热门回答(159 赞)

你可以手动迭代集合的元素:

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

你经常会看到这个模式使用aforloop而不是awhileloop:

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

正如人们所指出的那样,使用aforloop是首选,因为它将迭代器变量(在这种情况下为i)限制在较小的范围内。


#2 热门回答(17 赞)

之所以得到aConcurrentModificationException是因为条目是通过删除的Set.remove(),而不是Iterator.remove().如果通过删除了一个条目Set.remove(),当迭代完成时,你将得到一个ConcurrentModificationException。另一方面,在这种情况下,支持通过**Iterator.remove()**删除条目。

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

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

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

#3 热门回答(9 赞)

你还可以重构你的解决方案,删除第一个循环:

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

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

set.removeAll(removeCandidates);

原文链接