Collection根据Collection的内容抛出或不抛出ConcurrentModificationException [英] Collection throws or doesn't throw ConcurrentModificationException based on the contents of the Collection

查看:122
本文介绍了Collection根据Collection的内容抛出或不抛出ConcurrentModificationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下Java代码按预期抛出 ConcurrentModificationException

The following Java code throws a ConcurrentModificationException, as expected:

public class Evil
{
    public static void main(String[] args) {
        Collection<String> c = new ArrayList<String>();
        c.add("lalala");
        c.add("sososo");
        c.add("ahaaha");
        removeLalala(c);
        System.err.println(c);
    }
    private static void removeLalala(Collection<String> c) 
    {
        for (Iterator<String> i = c.iterator(); i.hasNext();) {
            String s = i.next();
            if(s.equals("lalala")) {
                c.remove(s);
            }
        }
    }
}

但是以下示例仅在 Collection 的内容上有所不同,执行时没有任何异常:

But the following example, which differs only in the contents of the Collection, executes without any exception:

public class Evil {
    public static void main(String[] args) 
    {
        Collection<String> c = new ArrayList<String>();
        c.add("lalala");
        c.add("lalala");
        removeLalala(c);
        System.err.println(c);
    }
    private static void removeLalala(Collection<String> c) {
        for (Iterator<String> i = c.iterator(); i.hasNext();) {
            String s = i.next();
            if(s.equals("lalala")) {
                c.remove(s);
            }
        }
    }
}

这个打印输出[lalala]。为什么第二个示例在第一个示例出现时抛出 ConcurrentModificationException

This prints the output "[lalala]". Why doesn't the second example throw a ConcurrentModificationException when the first example does?

推荐答案

简短回答



因为迭代器的失败快速行为无法保证。

Short answer

Because the fail-fast behavior of an iterator isn't guaranteed.

你得到这个例外是因为除了通过迭代器之外你不能在迭代它时操纵一个集合。

You're getting this exception because you cannot manipulate a collection while iterating over it, except through the iterator.

错误:

// we're using iterator
for (Iterator<String> i = c.iterator(); i.hasNext();) {  
    // here, the collection will check it hasn't been modified (in effort to fail fast)
    String s = i.next();
    if(s.equals("lalala")) {
        // s is removed from the collection and the collection will take note it was modified
        c.remove(s);
    }
}

好:

// we're using iterator
for (Iterator<String> i = c.iterator(); i.hasNext();) {  
    // here, the collection will check it hasn't been modified (in effort to fail fast)
    String s = i.next();
    if(s.equals("lalala")) {
        // s is removed from the collection through iterator, so the iterator knows the collection changed and can resume the iteration
        i.remove();
    }
}






现在转到为什么:在上面的代码中,注意如何执行修改检查 - 删除将集合标记为已修改,下一次迭代检查任何修改,如果检测到集合已更改则失败。另一个重要的事情是 ArrayList (不确定其他集合)检查 hasNext()中的修改


Now to the "why": In the code above, notice how the modification check is performed - the removal marks the collection as modified, and next iteration checks for any modifications and fails if it detects the collection changed. Another important thing is that ArrayList (not sure about other collections) does not check for modification in hasNext().

因此,可能会发生两件奇怪的事情:

Therefore, two strange things may happen:


  • 如果在迭代时删除最后一个元素,则不会抛出任何内容


    • 这是因为没有next元素,因此迭代在到达修改之前结束 - 检查代码


    • 所以即使在这种情况下,删除后也没有下一个元素

    请注意,这一切都符合 ArrayList的文档

    Note that this all is in line with ArrayList's documentation:


    请注意,无法保证迭代器的快速失败行为,因为一般来说,在存在不同步的并发修改时,不可能做出任何硬性保证。失败快速迭代器会尽最大努力抛出ConcurrentModificationException。因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的故障快速行为应该仅用于检测错误。

    Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.



    编辑添加:



    这个问题提供了一些信息,说明为什么在 hasNext()中执行的并发修改检查?并且仅在 next()中执行。

    Edited to add:

    This question provides some information on why the concurrent modification check is not performed in hasNext() and is only performed in next().

    这篇关于Collection根据Collection的内容抛出或不抛出ConcurrentModificationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆