枚举是在抛出concurrentModification异常。为什么?

时间:2017-06-05 09:58:36

标签: java

枚举是故障安全的。故障安全迭代器将用于克隆原始集合。那么为什么它会抛出concurrentModificationException?请澄清。

请找到我的代码:

public static void main(String[] args) {

    Vector<String> v=new Vector<String>();
    v.add("Amit");
    v.add("Raj");
    v.add("Pathak");
    v.add("Sumit");
    v.add("Aron");
    v.add("Trek");

    Enumeration en=(Enumeration) Collections.enumeration(v);

    while(en.hasMoreElements())
    {
        String value=(String) en.nextElement();
        System.out.println(value);
        v.remove(value);//modifying the collection

    }

}

找到下面的错误消息

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.Vector$Itr.checkForComodification(Unknown Source)
at java.util.Vector$Itr.next(Unknown Source)
at java.util.Collections$2.nextElement(Unknown Source)
at valar.org.src.EnumerationTest.main(EnumerationTest.java:24)

4 个答案:

答案 0 :(得分:2)

Collections.enumeration(Collection)将从作为参数传递的集合中创建一个迭代器:

public static <T> Enumeration<T> enumeration(final Collection<T> c) {
    return new Enumeration<T>() {
        private final Iterator<T> i = c.iterator();

        public boolean hasMoreElements() {
            return i.hasNext();
        }

        public T nextElement() {
            return i.next();
        }
    };
}

这意味着迭代器被支持到你在迭代器循环中删除元素的集合,你不能删除使用迭代器迭代的集合的元素。

您应该在Vector调用中创建enumeration()的副本:

Enumeration<String> en = Collections.enumeration(new Vector<String>(v));

作为旁注,您应该支持List接口和ArrayList实现Vector(已同步)并声明备用转换,并增加类型的安全性代码。

所以它会给出这个代码(我离开Vector使用,因为它可能是一个不可修改的约束,但我指定了泛型,因为它甚至在遗留代码中添加通常更简单):

Vector<String> v = new Vector<String>();
v.add("Amit");
v.add("Raj");
v.add("Pathak");
v.add("Sumit");
v.add("Aron");
v.add("Trek");

Enumeration<String> en = Collections.enumeration(new Vector<String>(v));

while (en.hasMoreElements()) {
    String value = (String) en.nextElement();
    System.out.println(value);
    v.remove(value);// modifying the collection
}

答案 1 :(得分:1)

您的枚举在内部使用Iterator。迭代元素时,不能使用向量本身来删除项目。你必须使用迭代器。但是你无法访问它。改为创建一个迭代器:

public static void main(String[] args) {

    final Vector<String> v = new Vector<String>();
    v.add("Amit");
    v.add("Raj");

    // Use an Iterator to remove the value you are iterating over
    final Iterator<String> iterator = v.iterator();

    while (iterator.hasNext()) {
        final String value = iterator.next();
        System.out.println(value);
        iterator.remove();
    }
}

尽管Vector实际上已经被弃用了。您应该改为使用List:

正确列表的导入(不要使用awt.List):

import java.util.ArrayList;
import java.util.List;

更改后的代码:

public static void main(String[] args) {

    final List<String> v = new ArrayList<>();
    v.add("Amit");
    v.add("Raj");
    v.add("Pathak");

    final Iterator<String> iterator = v.iterator();

    while (iterator.hasNext()) {
        final String value = iterator.next();
        System.out.println(value);
        iterator.remove();
    }
}

另请注意,您可以将接口用作Type,这通常是使用该实现的首选。

编辑:

看看你的例子,也许你真正需要的是一个队列:

public static void main(String[] args) {

    final Queue<String> v = new LinkedList<>();
    v.add("Amit");
    v.add("Raj");
    v.add("Pathak");

    System.out.println("Size: " + v.size());
    for (String element = v.poll(); element != null; element = v.poll()) {
        System.out.println(element);
    }
    System.out.println("Size: " + v.size());
}

输出:

Size: 3
Amit
Raj
Pathak
Size: 0

这与您的示例相同。有关收藏集的详细信息,请参阅The official Collections Java Trail

答案 2 :(得分:0)

  

枚举是故障安全的。

正确。 (允许一些语言困难。)

  

故障安全迭代器将用于克隆原始集合。

正确。 (允许一些语言困难。)

  

那为什么它会抛出concurrentModificationException?

因为没有涉及克隆。

克隆在哪里?

答案 3 :(得分:0)

你正在使用不支持删除方法的Enumeration。一旦你创建了一个Enumeration,它就会测试checkForComodification。所以当你从向量中删除时,modCount会增加,而且expectModCount也不会被修改。

 final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

请使用迭代器修改您的代码

public static void main(String[] args) {

        Vector<String> v = new Vector<String>();
        v.add("Amit");
        v.add("Raj");
        v.add("Pathak");
        v.add("Sumit");
        v.add("Aron");
        v.add("Trek");

        Iterator<String> it =v.iterator();

        while (it.hasNext()) {
            String value = it.next();
            System.out.println(value);
            it.remove();

        }

    }