迭代时从 HashSet 中删除元素
因此,如果我在迭代时尝试从 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);
谢谢!
So, if I try to remove elements from a Java HashSet while iterating, I get a ConcurrentModificationException. What is the best way to remove a subset of the elements from a HashSet as in the following example?
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);
Here is a solution, but I don't think it's very elegant:
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);
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
就像木材所说 - “Java 8 Collection 有一个很好的方法,称为removeIf,它使事情变得更容易和更安全”
这是解决您的问题的代码:
现在您的集合仅包含奇数值。
Like timber said - "Java 8 Collection has a nice method called removeIf that makes things easier and safer"
Here is the code that solve your problem:
Now your set contains only odd values.
这是更现代的流方法:
但是,这会创建一个新集合,因此如果它是一个非常大的集合,那么内存限制可能会成为一个问题。
编辑:这个答案的先前版本建议使用 Apache CollectionUtils,但那是在 steam 出现之前。
Here's the more modern streams approach:
However, this makes a new set, so memory constraints might be an issue if it's a really huge set.
EDIT: previous version of this answer suggested Apache CollectionUtils but that was before steams came about.
另一种可能的解决方案:
或者:
An other possible solution:
Or:
您可以手动迭代集合的元素:
您经常会看到使用
for
循环而不是while
循环的这种模式:正如人们所指出的,使用 < code>for 循环是首选,因为它将迭代器变量(在本例中为
i
)限制在较小的范围内。You can manually iterate over the elements of the set:
You will often see this pattern using a
for
loop rather than awhile
loop:As people have pointed out, using a
for
loop is preferred because it keeps the iterator variable (i
in this case) confined to a smaller scope.您收到
ConcurrentModificationException
的原因是因为通过 Set.remove()(而不是 Iterator.remove())删除条目。 如果在迭代完成时通过 Set.remove() 删除条目,您将收到 ConcurrentModificationException。 另一方面,在这种情况下支持迭代时通过 Iterator.remove() 删除条目。新的 for 循环很好,但不幸的是它在这种情况下不起作用,因为您不能使用 Iterator 引用。
如果需要在迭代时删除条目,则需要使用直接使用迭代器的长形式。
The reason you get a
ConcurrentModificationException
is because an entry is removed via Set.remove() as opposed to Iterator.remove(). If an entry is removed via Set.remove() while an iteration is being done, you will get a ConcurrentModificationException. On the other hand, removal of entries via Iterator.remove() while iteration is supported in this case.The new for loop is nice, but unfortunately it does not work in this case, because you can't use the Iterator reference.
If you need to remove an entry while iteration, you need to use the long form that uses the Iterator directly.
Java 8 Collection 有一个名为removeIf 的好方法,它使事情变得更简单、更安全。 来自 API 文档:
有趣的注释:
来自:
https: //docs.oracle.com/javase/8/docs/api/java/util/Collection.html#removeIf-java.util.function.Predicate-
Java 8 Collection has a nice method called removeIf that makes things easier and safer. From the API docs:
Interesting note:
From:
https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#removeIf-java.util.function.Predicate-
您还可以重构您的解决方案,删除第一个循环:
you can also refactor your solution removing the first loop: