为什么这段代码会抛出ConcurrentModificationException?

时间:2013-02-05 21:49:31

标签: java iterator set

编写一个方法removeEvenLength,它将一组字符串作为参数,并从集合中删除所有偶数长度的字符串。

我的解决方案:

public static void removeEvenLength(Set<String> set) {
    for(String word : set) {
        if(word.length() % 2 == 0) {
            set.remove(word);
        }
    }
}

输入: [foo, buzz, bar, fork, bort, spoon, !, dude]

输出:

ConcurrentModificationException on line 2:
java.util.ConcurrentModificationException
    at java.util.TreeMap$PrivateEntryIterator.nextEntry(TreeMap.java:1115)
    at java.util.TreeMap$KeyIterator.next(TreeMap.java:1169)
    at removeEvenLength (Line 2)

所以我可以通过创建Iterator来解决它。但我想知道为什么上面的代码不起作用?

编辑:

Iterator也不起作用:

public static void removeEvenLength(Set<String> set) {
    Iterator<String> i = set.iterator();
    while(i.hasNext()) {
        String word = i.next();
        if(word.length() % 2 == 0) {
            set.remove(word);
        }
    }
}

同样的错误。

2 个答案:

答案 0 :(得分:5)

在此迭代中,隐式创建了iterator对象。当你有iterator时,你可以只从迭代器中改变集合。在这种情况下,您将直接删除对象,这就是抛出此异常的原因。

创建迭代器,并使用迭代器删除对象:

iterator.remove(); // removes current element

答案 1 :(得分:2)

要了解ConcurrentModificationException出现的原因,您将了解fail-fast迭代的概念。如果一个线程正在迭代一个集合,并且它意识到正在进行迭代时正在修改集合,那么迭代器将抛出一个异常,而不是“可能”导致代码中的任何完整性问题。

当然,并非所有迭代器都遵循这种方法,并且使用Java Iterator几乎总能确保迭代在修改时永远不会失败。

要使用迭代器删除元素,请使用此代码

Iterator<String> iter = list.iterator();
    while(iter.hasNext()) {
        String obj = iter.next();
        if(<removal_condition_here>) {
            iter.remove();
        }
    }