ArrayList的删除异常

问题:

ArrayList在使用foreach循环对元素进行删除时,出现了.ConcurrentModificationException异常,删除第一个元素时没有报错,但是删除第二个元素却抛异常?

对于这个问题,我们更常听到的可能是不要再foreach循环中进行元素的remove和add操作。
带着这个问题做了一个简单的测试:

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");
    for (String s : list) {
        if (s.equals("1")){//s.equals("2")
            list.remove(s);
        }
    }
}

代码十分简单,在调试时,这里也有一些问题,在debug时不能仅仅关注ArrayList的remove方法,这样你会基本找不到问题所在,你会发现它都已经删除成功了,但是为什么还是抛了异常。

分析:

由于上面的for循环是走迭代器的所以我们需要看iterator相关的方法具体做了什么:

public boolean hasNext() {
    //cursor为当前元素的下标,size为当前list的长度(这里是为什么第一个元素不报错的关键点)
    return cursor != size;
}
 
 
 
private void fastRemove(int index) {
   //这里是抛出异常的关键点
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
}

为什么说上面的代码是第一个元素不报错的关键点呢?
我们根据上面的测试代码顺序走一遍(s.equals(“1”)):
在这里插入图片描述

只看这一个可能看不出什么门道,但是和下面的进行对比,就知道为什么报错了:
在这里插入图片描述

根据上面的流程我们看看next,为什么抛出异常:
在这里插入图片描述
在这里插入图片描述

我们根据上面的流程可以知道,modCount和expectedModCount已经不等了,所以抛出了异常。

什么情况下不抛异常:

在这里插入图片描述

cursor随着迭代的增加,而size随着remove的操作而减少(在一次迭代中只删除一次的情况下),最终出现相等的情况,导致hasNext判断为false,导致循环退出,而没有执行next判断(检查在next判断中),所以没有报错。
看下面这个例子(ArrayList中有4个元素):
在这里插入图片描述

如果我们在cursor为1的位置删除,执行完删除操作后,cursor为2,size为3,这时满足hasNext判断条件,继续执行next,结果抛出异常。
在这里插入图片描述

我们在cursor为2的位置删除,执行完删除操作后,cursor为3,size也为3,不满足hasNext的判断条件,不执行next操作,无异常抛出。
综上所述,可以看出在只删除一个元素的情况下,只有在当删除元素后,下一次hasNext判断为false,next操作不执行的情况才不会报错,而满足这个条件的位置也是固定的,就是集合中倒数第二个元素的位置(集合元素大于等于2)。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值