List 如何一边遍历,一边删除?

一. 第一时间想到的错误方式

  public static List<String> wrongDelete(List<String> list){
        for (String s:list){
            if ("a".equals(s)){
                list.remove(s);
            }
        }
        return list;
    }

然后就抛出了 并发修改异常。
在这里插入图片描述
看报错提示位置:
在这里插入图片描述
在这里插入图片描述
因为 foreach循环在实际执行时,其实使用的是Iterator的hasnext()和next()。
上面的代码实际执行相当于下面的:

    public static List<String> wrongDelete2(List<String> list) {
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            String s = it.next();
            if ("a".equals(s)) {
                list.remove(s);
            }
        }
        return list;
    }

调用next()方法获取下一个元素时,第一行代码就是调用了checkForComodification();,而该方法的核心逻辑就是比较modCount和expectedModCount这2个变量的值。
刚开始,我们往List里面add元素时,每次add,modCount++,所以在上面的示例中,刚开始modCount和expectedModCount的值都为3.
在这里插入图片描述
在这里插入图片描述
但是当执行完下面的一行代码:

list.remove(s);

在这里插入图片描述
在这里插入图片描述
modCount的值就被修改成了4。所以在第2次获取元素时,modCount和expectedModCount的值就不相等了,所以抛出了java.util.ConcurrentModificationException异常。

这里需要注意一点的是:如果要删除的元素是"b",则可以成功删除,不会报错.

    public static List<String> wrongDelete(List<String> list) {
        for (String s : list) {
            if ("b".equals(s)) {
                list.remove(s);
            }
        }
        return list;
    }

这里为啥又不报错呢?关键在于hasNext()的判断条件,回归源码:
在这里插入图片描述
在这里插入图片描述
上表列出了foreach每次循环完关键属性的值的变化,可以看到:当第二次循环完后,cursor == size,然后循环结束,不会在进入next(),从而判断 expectedCount == modCount ?,就不会报异常了.
使用普通for循环也是一样的,因为底层都会去调用Iterator的hasNext()和next()。

二. 如何解决呢?

主要有以下3种方法:

  1. 使用Iterator的remove()方法
 public static List<String> rightDelete(List<String> list) {
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            String s = it.next();
            if ("a".equals(s)) {
                it.remove();
            }
        }
        return list;
    }

在这里插入图片描述
可以看出,每次删除一个元素,都会将modCount的值重新赋值给expectedModCount,这样2个变量就相等了,不会触发java.util.ConcurrentModificationException异常。

  1. 使用for循环正序遍历
    public static List<String> rightDelete2(List<String> list) {
        for (int i = 0;i < list.size();i++) {
            String s = list.get(i);
            if ("a".equals(s)) {
                list.remove(i);
                i = i - 1;
            }
        }
        return list;
    }

这种实现方式比较好理解,就是通过数组的下标来删除,不过有个注意事项就是删除元素后,要修正下下标的值.

  1. 使用for循环倒序遍历
    public static List<String> rightDelete3(List<String> list) {
        for (int i = list.size() - 1;i >= 0;i--) {
            String s = list.get(i);
            if ("a".equals(s)) {
                list.remove(i);
            }
        }
        return list;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值