执行ArrayList的remove(object)方法抛异常?

栏目: IT技术 · 发布时间: 3年前

内容简介:或许有很多小伙伴都尝试过如下的代码:然后会发现抛出增强for循环是Java1.5后,Collection实现了Iterator接口后出现的。增强for循环的代码如下

简介

或许有很多小伙伴都尝试过如下的代码:

ArrayList<Object> list = ...;
for (Object object : list) {
    if (条件成立) {
        list.remove(object);
    }
}

然后会发现抛出 java.util.ConcurrentModificationException 异常,这是一个并发异常。那么这个到底是什么情况?首先需要介绍一下 增强for循环

增强for循环

增强for循环是 Java 1.5后,Collection实现了Iterator接口后出现的。增强for循环的代码如下

for (Object object : list) {
    // 操作
}

其实增强for循环就是使用Iterator迭代器进行迭代的,增强for循环就变成下面这样:

Iterator<Object> iterator = list.iterator();
while (iterator.hasNext()) {
    iterator.next();
    // 操作
}

那么为什么在增强for循环中调用 list.remove(object) 会出事呢?那么咱们看看ArrayList下的 Iterator的实现类: Itr类

Itr子类

Itr子类是Iterator的实现类,属于ArrayList私有的局部内部类。我截取了Itr类的部分代码,如下:

private class Itr implements Iterator<E> {
    int cursor;       // index of next element to return
    int expectedModCount = modCount;

    Itr() {}

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

    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();
        ...
    }
    
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

elementData是ArrayList存放元素的数组,上面代码没有贴出来。

size是elementData实际存放的容量大小

modCount记录elementData容量的修改次数

expectedModCount记录实例化迭代器Itr时,elementData容量的修改次数

注意!:在迭代器中,当执行 next 方法的时候,会去调用 checkForComodification 方法,判断elementData 的容量是否被修改过。

然后来看看ArrayList的remove(object)方法,截取部分代码如下:

public boolean remove(Object o) {
    for (int index = 0; index < size; index++)
	    if (找到目标元素) {
	        fastRemove(index);
	        return true;
	    }
	return false;
}

private void fastRemove(int index) {
    modCount++;
    // 移除操作
}

可以发现,调用remove(object)方法时调用了fastRemove方法,在fastRemove方法中执行 modCount++

现在把文章开头的代码拷下来,再来分析一次:

ArrayList<Object> list = ...;
for (Object object : list) {
    if (条件成立) {
        list.remove(object);
    }
}

当执行了 list.remove 时,执行 modCount++ 。此时迭代器再往下进行迭代,执行了next方法,发现 modCount != expectedModCount ,那么则抛出 java.util.ConcurrentModificationException 异常。 之所以Iterator认为是一个并发异常。是因为你不在迭代器里操作,而是在迭代器外面进行remove操作呀!

难道没有其他解决方案吗?有滴。

解决方案

那么就是使用Itr的 remove方法。Itr子类重写了 remove 方法,这里部分代码:

public void remove() {
    ...
    try {
        ArrayList.this.remove(需要删除元素的索引);
        ...
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}

其实很简单,就是remove后,把 expectedModCount 同步一下 modCount 的值,这就解决了。完整代码如下:

ArrayList<Object> list = ...;
Iterator<Object> iterator = list.iterator();
while (iterator.hasNext()) {
    iterator.next();
    iterator.remove();
}

总结

本来我还不知道增强for循环是调用Iterator进行迭代的,要不是我debug了一波,我还不知道呐。还是小有收货。

个人博客网址: https://colablog.cn/

如果我的文章帮助到您,可以关注我的微信公众号,第一时间分享文章给您

执行ArrayList的remove(object)方法抛异常?

以上所述就是小编给大家介绍的《执行ArrayList的remove(object)方法抛异常?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

顾客要买什么

顾客要买什么

[美]迈克尔·西尔 / 方海萍 / 中国人民大学出版社 / 2006-10 / 38.00元

《顾客要买什么》告诉我们全球的中产阶级如何正在改造着消费品市场:对低价的产品和服务进行趋低消费,对于高端的产品和服务要趋优消费,而对于日趋乏味、价值降低的中档商品则避而远之。这些消费者大多是女性,教育程度高,可支配收入多,买东西的时候也更会精打细算。她们选购、使用商品和服务的时候都是有目的的,有一种大权在握的感觉。消费对她们来说并不是非做不可的麻烦事,也不是什么无法避免的琐事,而是如何明智地花钱的......一起来看看 《顾客要买什么》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具