Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ConcurrentModificationException:.add()与.addAll()的比较_Java_Foreach_Concurrentmodification - Fatal编程技术网

Java ConcurrentModificationException:.add()与.addAll()的比较

Java ConcurrentModificationException:.add()与.addAll()的比较,java,foreach,concurrentmodification,Java,Foreach,Concurrentmodification,为什么会出现以下情况?难道这两个都不管用吗 List<String> items = data; for( String id : items ) { List<String> otherItems = otherData; // 1. addAll() //Causes ConcurrentModificationException items.addAll(otherItems); // 2. .ad

为什么会出现以下情况?难道这两个都不管用吗

List<String> items = data;
for( String id : items ) {
    List<String> otherItems = otherData;        

    // 1.   addAll()
    //Causes ConcurrentModificationException
    items.addAll(otherItems);

    // 2.   .add()
    //Doesn't cause exceptions
    for( String otherId : otherItems ) {
        items.add(otherId);
    }
}
列表项=数据;
用于(字符串id:items){
列出其他项目=其他数据;
//1.addAll()
//导致ConcurrentModificationException
items.addAll(其他项);
//2.添加()
//不会导致异常
for(字符串otherId:otherItems){
items.add(其他ID);
}
}
这是因为
add()
添加到集合项目中,但
addAll()
创建了一个新集合,从而将项目修改为列表的不同实例吗

编辑
其他项
都是具体类型的
数组列表

这里的for循环

for( String id : Items ) {
逻辑上与:

for(Iterator<String> it = Items.iterator(); it.hasNext();) {
    String id = it.next();

    ....
}
换句话说,通过迭代器进行添加,并避免ConcurrentModification

现在,谈谈为什么
add()
有效,而
addAll()
无效?我相信您可能只是看到了类似于add版本的东西,而迭代器中没有其他项,或者添加的值是emtpry,这可能是项实现中的一个bug。它应该抛出一个CME,而事实上它没有抛出一个,这意味着存在一个bug,不是在代码中,而是在集合中

他们都应该失败

但是:您随后发现
addAll()
正在添加一个空集合。空的addAll()不应导致CME。。。正如@Boann指出的,这是ArrayList实现中的一个bug

为了证明这一点,我进行了以下测试:

private static List<String> buildData() {
    return new ArrayList<>(Arrays.asList("Hello", "World"));
}

public static void testThings(List<String> data, List<String> addall, List<String> add) {
    System.out.printf("Using %s addAll %s and add %s%n", data, addall, add);

    try {
        for (String s : data) {
            if (addall != null) {
                data.addAll(addall);
            }
            if (add != null) {
                for (String a : add) {
                    data.add(a);
                }
            }
        }
        System.out.println("OK: " + data);
    } catch (Exception e) {
        System.out.println("Fail: " + e.getClass() + " -> " + e.getMessage());
    }
}

public static void main(String[] args) {

    String[] hw = {"Hello", "World"};

    testThings(buildData(), Arrays.asList(hw), null);
    testThings(buildData(), null, Arrays.asList(hw));
    testThings(new ArrayList<>(), Arrays.asList(hw), null);
    testThings(new ArrayList<>(), null, Arrays.asList(hw));
    testThings(buildData(), new ArrayList<>(), null);
    testThings(buildData(), null, new ArrayList<>());
    testThings(new ArrayList<>(), new ArrayList<>(), null);
    testThings(new ArrayList<>(), null, new ArrayList<>());
}
请注意以下两行:

Using [Hello, World] addAll [] and add null
Fail: class java.util.ConcurrentModificationException -> null
Using [Hello, World] addAll null and add []
OK: [Hello, World]

添加一个空的addAll会导致CME,但这不会从结构上修改列表。这是ArrayList中的一个错误。

这两个操作都不正确,因为它在迭代集合时会修改集合

检查表明,调用
add
addAll
应能在下一次循环迭代中成功抛出ConcurrentModificationException。对于
add
它没有这样做,这意味着对于特定版本的Java,ArrayList类中存在一个模糊的bug;或者(更可能)
otherItems
为空,因此在第二种情况下,实际上根本没有调用
add


我确信
其他项
必须是空的,因为如果添加到
列表中的项以您想要的方式“工作”,那么它将在循环中每次都增长,导致它无限循环,直到死于OutOfMemory错误。

我同意rolfl->在这两种情况下都应该抛出CME

最可能的答案:


addAll()是第一次调用,它抛出异常,第二段代码根本就不会到达->您忘记注释第一部分,因此认为add()-part是无异常代码;)

什么具体类型是
?因为您在项上打开了迭代器,而项不支持并发修改。为什么只允许你添加一个是真正的问题。不管怎样,你在这里做的事情可能不是你想要的。有趣的是,我一直认为你可以在结尾添加内容是有意的。我一直认为它可以添加到链中,但不能重新排列它。所以,在我缺乏经验的头脑中,这两种方法都应该奏效。我喜欢这样:“现在,如果你修改了一个迭代器迭代的列表,在迭代的中间,你就得到了CONTRONTRONMODIGATION异常。”你有什么资源可以让我读更多吗?@KickButtowski-The:这个类的迭代器和listIterator方法返回的迭代器是快速失效的:如果在迭代器创建后的任何时候,列表在结构上被修改,除了通过迭代器自己的remove或add方法,迭代器将抛出ConcurrentModificationException。关于是否应在
nasNext()
next()
或两个调用上抛出CME,规范不明确。java库只会在<代码> NEXT()/<代码>上进行,而不是<代码> HasNeXT()/<代码>,这是一些人认为是一个错误…由于这不是“快速失败”。感谢您链接这一点,我的假设是ArrayList.add()的工作方式类似于“迭代器自己的[add method]”,而.addAll()的工作方式则不同。您是对的,其他项从未被填充。如果里面有数据,它会失败,很好@FreakyDan-这意味着“其他项目”也不会导致CME。你问题中的代码搞乱了<空集合的code>addAll()不会导致CME。@FreakyDan-实际上,您可能在Java中发现了一个bug。。。嗯。我正在编辑我的答案。@rolfl
addAll
空集合确实会导致CME。查看ArrayList代码:
addAll
无条件调用
ensureCapacityInternal
,它无条件调用
ensureExplicitCapacity
,它无条件地执行
modCount++
。我现在看到了副作用。这是一个bug(在ArrayList中)。有趣。
Using [Hello, World] addAll [Hello, World] and add null
Fail: class java.util.ConcurrentModificationException -> null
Using [Hello, World] addAll null and add [Hello, World]
Fail: class java.util.ConcurrentModificationException -> null
Using [] addAll [Hello, World] and add null
OK: []
Using [] addAll null and add [Hello, World]
OK: []
Using [Hello, World] addAll [] and add null
Fail: class java.util.ConcurrentModificationException -> null
Using [Hello, World] addAll null and add []
OK: [Hello, World]
Using [] addAll [] and add null
OK: []
Using [] addAll null and add []
OK: []
Using [Hello, World] addAll [] and add null
Fail: class java.util.ConcurrentModificationException -> null
Using [Hello, World] addAll null and add []
OK: [Hello, World]