list删除数据有坑勿跳

有人看到这么标题可能觉得这个真是太easy了,不就remove吗,分分钟搞定。但结果却出乎意料,下面我们来说说list删除数据可能遇到的坑:

首先我们来初始化一个list

复制代码
public static void main(String[] args) {
ArrayList list=new ArrayList<>();
list.add(“华为”);
list.add(“中软”);
list.add(“平安”);
list.add(“富士康”);
list.add(“富士康”);
list.add(“软通”);
list.add(“苏宁”);
System.out.println(list);
复制代码

坑一:

我在list里添加一些各位大佬们以后要去的公司,突然想把里面的富士康删除掉。于是

1
2
3
4
5
6
for (int i = 0; i < list.size(); i++) {
if (“富士康”.equals(list.get(i))) {
list.remove(i);
}
}
System.out.println(list);
结果输出:[华为, 中软, 平安, 富士康, 软通, 苏宁]

两个富士康还剩一个,不彻底嘛。原因很简单,就是List调用remove(index)方法后,会移除index位置上的元素,index之后的元素就全部依次左移。第二个"富士康"自然躲过一劫。

这时可以对索引同步调整下,代码如下:

复制代码
for (int i = 0; i < list.size(); i++) {
if (“富士康”.equals(list.get(i))) {
list.remove(i–);
}
}

    System.out.println(list);

复制代码
结果为:[华为, 中软, 平安, 软通, 苏宁]

坑二:

使用foreach遍历List删除元素,代码如下:

复制代码
for (String str : list) {
if (“富士康”.equals(str)) {
list.remove(str);
}
}

    System.out.println(list);

复制代码
结果如下:

Exception in thread “main” java.util.ConcurrentModificationException

居然报错,什么原因呢?其实foreach 是对的 Iterable、hasNext、next方法的简写。我们可以看看List.iterator()的源码:

复制代码
private class Itr implements Iterator {
int cursor; // 要返回的下一个元素的索引
int lastRet = -1; // 返回的最后一个元素的索引;如果没有就返回-1
int expectedModCount = modCount;

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

    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }

    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

复制代码
可以看出在 next、remove方法中都会调用checkForComodification 方法,该方法的作用是判断 modCount != expectedModCount是否相等,

如果不相等则抛出ConcurrentModificationException异常

当我们调用 list.remove(item)时,对 list 对象的 modCount 值进行了修改,

而 list 对象的迭代器的 expectedModCount 值未进行修改

所以就抛出ConcurrentModificationException异常!

但我们可以用迭代器来删除list数据,代码如下:

    Iterator<String> it=list.iterator();
    while(it.hasNext()){
        if("富士康".equals(it.next())){
            it.remove();
        }
    }

结果:[华为, 中软, 平安, 软通, 苏宁]

这是因为Iterator.remove() 方法会在删除当前迭代对象的同时,会保留原来元素的索引。

所以用迭代删除元素是最保险的方法,建议大家使用List过程中需要删除元素时,使用这种方式。

这里需要注意的是如果使用迭代器,用list.remove(str)方法删除元素,还是会抛ConcurrentModificationException异常。原因上面已经讲过!

总结:

1、用for循环遍历List删除元素时,需要注意索引会左移的问题。

2、List删除元素时,为避免陷阱,建议使用迭代器iterator的remove方式。

3、List删除元素时,默认按索引删除,而不是对象删除。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值