• list删除数据有坑勿跳


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

    首先我们来初始化一个list

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

    坑一:

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

    	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<E> {
            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删除元素时,默认按索引删除,而不是对象删除。

  • 相关阅读:
    在微信移动端input file拍照或从相册选择照片后会自动刷新页面退回到一开始网站进入的页面
    华为手机点击按钮跳转链接不生效!!!
    css content 如何自定义生成图标?
    快速上手制作Icon Font
    一款全兼容的播放器 videojs
    video.js使用教程API
    jquery ajax 请求参数详细说明 及 实例
    前端性能优化
    Bootstrap3 CSS样式基本用法总结
    h5页面的公共css
  • 原文地址:https://www.cnblogs.com/zzjlxy-225223/p/11215732.html
Copyright © 2020-2023  润新知