你在这里的 for 循环
for( String id : Items ) {
逻辑上等同于:
for(Iterator<String> it = Items.iterator(); it.hasNext();) {
String id = it.next();
....
}
现在,如果您修改迭代器迭代的列表,在迭代过程中,您会得到 ConcurrentModificationException。来自Javadoc for ArrayList:
此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时候对列表进行结构修改,除了通过迭代器自己的 remove 或 add 方法之外的任何方式,迭代器将抛出一个 ConcurrentModificationException。
所以,addAll() 正在修改 Items,并导致迭代器失败。
您唯一的解决方案是:
- 不要执行 addAll()
-
用迭代器切换到循环,然后做:
for (String other : otherItems) {
it.add(other);
}
换句话说,通过迭代器进行添加,并避免 ConcurrentModification....
现在,关于为什么 add() 有效,而 addAll() 无效?我相信您可能只是在迭代器中没有其他项目时看到类似添加版本的内容,或者正在添加的值是空的,也许是项目实现中的错误。它应该抛出一个 CME,而它没有抛出一个事实意味着存在一个错误,不是在您的代码中,而是在集合中。
他们都应该失败!
但是:您随后发现addAll() 正在添加一个空集合。一个空的 addAll() 不应该导致 CME ......而且,正如@Boann 所指出的,这是 ArrayList 实现中的一个错误。
我整理了以下测试来证明这一点:
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 [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]
添加一个空的 addAll 会导致 CME,但这不会在结构上修改列表。这是 ArrayList 中的一个错误。