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

所以,如果我尝试移除元素从一个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().

自:https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#removeIf-java.util.function.Predicate-

像木材述-"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);
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top