小编典典

为什么在此示例中我没有收到 java.util.ConcurrentModificationException?

all

注意:我知道Iterator#remove()方法。

在下面的代码示例中,我不明白为什么List.removeinmain方法会 throws
ConcurrentModificationException,但 不是 inremove方法。

public class RemoveListElementDemo {    
    private static final List<Integer> integerList;

    static {
        integerList = new ArrayList<Integer>();
        integerList.add(1);
        integerList.add(2);
        integerList.add(3);
    }

    public static void remove(Integer toRemove) {
        for(Integer integer : integerList) {
            if(integer.equals(toRemove)) {                
                integerList.remove(integer);
            }
        }
    }

    public static void main(String... args) {                
        remove(Integer.valueOf(2));

        Integer toRemove = Integer.valueOf(3);
        for(Integer integer : integerList) {
            if(integer.equals(toRemove)) {                
                integerList.remove(integer);
            }
        }
    }
}

阅读 192

收藏
2022-08-05

共1个答案

小编典典

原因如下:正如 Javadoc 中所说:

此类的 iterator 和 listIterator
方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间对列表进行结构修改,除了通过迭代器自己的 remove 或 add
方法之外的任何方式,迭代器将抛出 ConcurrentModificationException。

这个检查是在next()迭代器的方法中完成的(你可以从堆栈跟踪中看到)。next()但是只有在传递为 true
时我们才会到达该方法hasNext(),这就是 for each 调用的方法,以检查是否满足边界。在您的 remove
方法中,当hasNext()检查是否需要返回另一个元素时,它会看到它返回了两个元素,现在在删除一个元素后,列表只包含两个元素。所以一切都很顺利,我们完成了迭代。不会发生并发修改的检查,因为这是在next()从未调用的方法中完成的。

接下来我们进入第二个循环。在我们删除第二个数字后,hasNext
方法将再次检查是否可以返回更多值。它已经返回了两个值,但列表现在只包含一个。但是这里的代码是:

public boolean hasNext() {
        return cursor != size();
}

1 != 2,所以我们继续这个next()方法,它现在意识到有人一直在弄乱列表并触发异常。

希望能解决你的问题。

概括

List.remove()``ConcurrentModificationException当它从列表中删除倒数第二个元素时不会抛出。

2022-08-05