Remove Elements from a HashSet while Iterating
因此,如果我试图在迭代过程中从Java哈希集中删除元素,则会得到一个CONTRONTRONMODIGATION异常。如下面的示例所示,从哈希集中删除元素子集的最佳方法是什么?
1 2 3 4 5 6 7 8 9 | 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); |
这是一个解决方案,但我认为它不太优雅:
1 2 3 4 5 6 7 8 9 10 11 | 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 2 3 4 5 6 7 | Iterator<Integer> iterator = set.iterator(); while (iterator.hasNext()) { Integer element = iterator.next(); if (element % 2 == 0) { iterator.remove(); } } |
您经常会看到使用
1 2 3 4 5 6 | for (Iterator<Integer> i = set.iterator(); i.hasNext();) { Integer element = i.next(); if (element % 2 == 0) { i.remove(); } } |
正如人们所指出的,使用
获得
新的for循环很好,但不幸的是,它在本例中不起作用,因为您不能使用迭代器引用。
如果您需要在迭代时删除一个条目,那么您需要使用直接使用迭代器的长格式。
1 2 3 4 5 6 | for (Iterator<Integer> it = set.iterator(); it.hasNext();) { Integer element = it.next(); if (element % 2 == 0) { it.remove(); } } |
Java 8集合有一个很好的方法,叫做ReaveIf,它使事情变得更容易和更安全。从API文档:
1 2 3 4 | default boolean removeIf(Predicate<? super E> filter) Removes all of the elements of this collection that satisfy the given predicate. Errors or runtime exceptions thrown during iteration or by the predicate are relayed to the caller. |
有趣的提示:
1 2 | The default implementation traverses all elements of the collection using its iterator(). Each matching element is removed using Iterator.remove(). |
来自:http://DOCS.COM/JavaSe/ 8 /DOCS/API/Java/UTL/Copy.html
您还可以重构解决方案,删除第一个循环:
1 2 3 4 5 6 7 8 | 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); |
就像木材说的那样:"Java 8的集合有一个很好的方法,叫做ReaveVE,它使事情变得更容易和更安全"。
下面是解决您问题的代码:
1 2 3 |
现在您的集合只包含奇数。
它是否需要在迭代时进行?如果您所做的只是过滤或选择,我建议您使用ApacheCommonsCollectionUtils。这里有一些强大的工具,它使您的代码"更酷"。
下面是一个实现,它应该提供您所需要的:
1 2 3 4 5 6 |
如果您发现自己经常使用同一种谓词,那么可以将其提取到静态变量中以便重用…把它命名为类似于
另一种可能的解决方案:
1 2 3 4 5 |
或:
1 2 3 4 5 6 7 |