问题
这个问题在这里已有答案:
- 迭代集合,在循环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();
}
}
你经常会看到这个模式使用afor
loop而不是awhile
loop:
for (Iterator<Integer> i = set.iterator(); i.hasNext();) {
Integer element = i.next();
if (element % 2 == 0) {
i.remove();
}
}
正如人们所指出的那样,使用afor
loop是首选,因为它将迭代器变量(在这种情况下为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);