Java - Collection.remove() 在不同条件下表现不同

NIN*_*OOP 1 java collections iterator

这是对我之前的问题的跟进:

集合 - Iterator.remove() 与 Collection.remove()

下面的两段代码,显然只有一行不同,但一个抛出异常,另一个不抛出。你能解释一下区别吗?

 List<String> list = new ArrayList<String>
(Arrays.asList("noob1","noob2","noob3"));


System.out.println(list);

for (String str : list) {
    if (str.equals("noob2")) {
        list.remove(str);
    }
}
Run Code Online (Sandbox Code Playgroud)

运行良好,但如果我将条件更改为

if (!str.equals("noob2"))
Run Code Online (Sandbox Code Playgroud)

代码抛出异常!

Pet*_*rey 5

在这种情况下会发生什么是您正在删除第二个列表元素。

List<String> list = new ArrayList<String>
        (Arrays.asList("noob1", "noob2", "noob3", "noob4"));

System.out.println(list);

for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
    String str = iterator.next();
    if (str.equals("noob3")) {
        System.out.println("Checking "+str);
        list.remove(str);
    }
}
System.out.println(list);
Run Code Online (Sandbox Code Playgroud)

印刷

[noob1, noob2, noob3, noob4]
Checking noob1
Checking noob2
Checking noob3
[noob1, noob2, noob4]
Run Code Online (Sandbox Code Playgroud)

通过删除倒数第二个元素,您已将大小减小到您迭代的元素数量。

// from ArrayList.Itr
    public boolean hasNext() {
        return cursor != size;
    }
Run Code Online (Sandbox Code Playgroud)

这会导致循环在 中执行并发修改检查之前提前退出next()。如果您删除任何其他元素,next()则调用并获得 CME。

顺便说一句,也绕过检查的东西是

for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
    String str = iterator.next();
    System.out.println("Checking "+str);
    if (str.equals("noob2")) {
        list.remove("noob1");
        list.remove("noob3");
    }
}
Run Code Online (Sandbox Code Playgroud)

只要集合的大小与它达到的索引相同,就不会执行检查。