删除元素。同时迭代[重复]
题
这个问题已经有一个答案在这里:
所以,如果我尝试移除元素从一个Java 。 虽然循环,我得到一个 ConcurrentModificationException.什么是最好的方式来删除的一个子集的元素 。 如下面的例子吗?
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);
谢谢!
解决方案
你可以手动迭代要素设定:
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
if (element % 2 == 0) {
iterator.remove();
}
}
你会经常看到这种模式的使用 for
循环,而不是一个 while
循环:
for (Iterator<Integer> i = set.iterator(); i.hasNext();) {
Integer element = i.next();
if (element % 2 == 0) {
i.remove();
}
}
因为人们已经指出,使用 for
回路是最佳的,因为它不断迭代变量(i
在这种情况下)局限于小范围。
其他提示
因为你得到一个 ConcurrentModificationException
是因为一个条目被删除,通过 设置。删除() 作为反对 迭代器。删除().如果一个条目被删除,通过 设置。删除() 迭代的同时正在做,你会得到一个ConcurrentModificationException.另一方面,去除的项目通过 迭代器。删除() 同时迭代的支持,在这种情况。
新的循环是不错的,但不幸的是它不工作,在这种情况下,因为你不能使用的迭代基准。
如果你需要删除一个项目,同时迭代,需要使用长的形式,使用的迭代。
for (Iterator<Integer> it = set.iterator(); it.hasNext();) {
Integer element = it.next();
if (element % 2 == 0) {
it.remove();
}
}
你也可以"重构"解决方案中去除的第一个循环:
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);
Java8集有一个很好的方法称为removeIf,使事情变得更容易,更安全。从API文档:
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.
有趣的注意:
The default implementation traverses all elements of the collection using its iterator().
Each matching element is removed using Iterator.remove().
像木材述-"Java8集有一个很好的方法称为removeIf,使事情变得更容易,更安全"
这里是代码解决你的问题:
set.removeIf((Integer element) -> {
return (element % 2 == 0);
});
现在你只包含奇数值。
它不会需要,同时循环?如果你正在做的是筛选或选择,我建议使用Apache Commons CollectionUtils.有一些强大的工具,它使你的代码"冷却器"。
这里有一个执行情况,应该提供你所需要的:
Set<Integer> myIntegerSet = new HashSet<Integer>();
// Integers loaded here
CollectionUtils.filter( myIntegerSet, new Predicate() {
public boolean evaluate(Object input) {
return (((Integer) input) % 2 == 0);
}});
如果你发现自己使用同一种谓常你可以拉得到一个静态变为再利用...名这样的东西 EVEN_NUMBER_PREDICATE
.有些人可能会看到那个码,并宣布它"难于阅读",但它看起来更清洁当你拉出谓入一个静态的。然后很容易看出,我们正在做一个 CollectionUtils.filter(...)
而这似乎更具可读性(对我),比一堆的循环,所有超过创造的。
其他可能的解决方案:
for(Object it : set.toArray()) { /* Create a copy */
Integer element = (Integer)it;
if(element % 2 == 0)
set.remove(element);
}
或者:
Integer[] copy = new Integer[set.size()];
set.toArray(copy);
for(Integer element : copy) {
if(element % 2 == 0)
set.remove(element);
}