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。。。嗯。我正在编辑我的答案。@rolfladdAll
空集合确实会导致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]