Java Enumeration vs Iterator

ami*_*ngh 12 java

Enumeration不扔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<String> en=v.elements();

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

    }

}
Run Code Online (Sandbox Code Playgroud)

它只打印:

Amit
Pathak
Aron

为什么会出现这种情况.我们可以说这Enumerator是线程安全的吗?

编辑:使用Iterator时,它会抛出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=(String) it.next();
        System.out.println(value);
        v.remove(value);
    }
}
Run Code Online (Sandbox Code Playgroud)

请检查.

sfu*_*ger 12

请注意,ConcurrentModificationException与多线程或线程安全意义上的并发性无关.有些集合允许并发修改,有些则不允许.通常,您可以在文档中找到答案.但并发并不意味着不同的线程同时发生.这意味着您可以在迭代时修改集合.

ConcurrentHashMap是一种特殊情况,因为它在迭代时被明确定义为线程安全且可编辑(我认为对于所有线程安全集合都是如此).

无论如何,只要您使用单个线程来迭代和修改集合,ConcurrentHashMap就是您的问题的错误解决方案.您错误地使用了API.您应该使用Iterator.remove()来删除项目.或者,您可以在迭代和修改原始文件之前复制该集合.

编辑:

我不知道任何抛出ConcurrentModificationException的Enumeration.但是,并发修改时的行为可能与您预期的不同.正如您在示例中看到的,枚举会跳过列表中的每个第二个元素.这是因为它的内部索引随着删除而递增.所以这就是:

  • en.nextElement() - 从Vector返回第一个元素,将index增加到1
  • v.remove(value) - 从Vector中移除第一个元素,向左移动所有元素
  • en.nextElement() - 从Vector返回第二个元素,现在是"Pathak"

Iterator的快速失败行为可以保护您免受此类事件的影响,这就是为什么它通常比Enumberation更好.相反,您应该执行以下操作:

Iterator<String> it=v.iterator();
while(it.hasNext())
{
    String value=(String) it.next();
    System.out.println(value);
    it.remove(); // not v.remove(value); !!
}
Run Code Online (Sandbox Code Playgroud)

或者:

for(String value : new Vector<String>(v)) // make a copy
{
    String value=(String) it.next();
    System.out.println(value);
    v.remove(value);
}
Run Code Online (Sandbox Code Playgroud)

第一个肯定是可取的,因为只要您按照预期使用API​​,您就不需要副本.


Mar*_*inK 4

枚举不会抛出 ConcurrentModificationException ,为什么?

因为正在调用的代码中没有抛出此异常的路径。编辑:我指的是 Vector 类提供的实现,而不是一般的 Enumeration 接口。

为什么会出现这样的行为。我们可以说 Enumerator 是线程安全的吗?

从某种意义上说,它是线程安全的,执行的代码是正确同步的。然而,我不认为你的循环产生的结果是你想要的。

输出的原因是 Enumeration 对象维护一个计数器,该计数器在每次调用 后都会递增nextElement()。该计数器不知道您对 的调用remove()