• 循环删除List集合的元素


    1、for循环方式删除元素

    public class Main
    {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            list.add("a");
            list.add("b");
            list.add("c");
            list.add("d");
            list.add("e");
    
            System.out.println("删除前的list:" + list.toString());
            for (int i = 0, len = list.size(); i < len; i++) {
                if ("c".equals(list.get(i))) {
                    list.remove(i);
                }
            }
            System.out.println("删除后的list" + list.toString());
        }
    }
    
    执行结果:
    删除前的list:[a, b, c, d, e]
    Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 4, Size: 4
    	at java.util.ArrayList.rangeCheck(ArrayList.java:653)
    	at java.util.ArrayList.get(ArrayList.java:429)
    	at Main.main(Main.java:17)
    
    

    remove删除后,会将后续元素前移一位,并且size减去1。

    public E remove(int index) {
        rangeCheck(index);
        modCount++;
        E oldValue = elementData(index);
        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
        return oldValue;
    }
    

    get的时候,首先调用rangeCheck()验证索引是否越界。

    上面案例中len设为了最初的长度5,后面删除掉元素后仍是按照5的长度来遍历,导致越界

    public E get(int index) {
        rangeCheck(index);
        checkForComodification();
        return ArrayList.this.elementData(offset + index);
    }
    
    private void rangeCheck(int index) {
        if (index < 0 || index >= this.size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    

    可以将遍历size改成动态 for (int i = 0; i < list.size(); i++)

    2、增强for循环方式删除元素

    
    public class Main
    {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            list.add("a");
            list.add("b");
            list.add("c");
            list.add("d");
            list.add("e");
            list.add("f");
    
            System.out.println("删除前的list:" + list.toString());
            for (String s : list) {
                if ("c".equals(s)) {
                    list.remove(s);
                }
            }
            System.out.println("删除后的list" + list.toString());
    
        }
    }
    
    运行输出:
    删除前的list:[a, b, c, d, e, f]
    Exception in thread "main" java.util.ConcurrentModificationException
    	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    	at java.util.ArrayList$Itr.next(ArrayList.java:851)
    	at Main.main(Main.java:16)
    

    增强循环本质上是迭代器循环,删除时用的元素内容匹配删除,其中会执行fastRemove()来真正删除,fastRemove()中会对modCount加1,modCount代表对ArrayList的修改次数。

    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    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
    }
    

    当后面再次取值的时候,先调用hasNext()判断是否已经取到最后一个值。

    然后调用next()取值,next()会调用 checkForComodification()进行验证,发现modCount和expectedModCount不相等,抛出异常。

    expectedModCount,是ArrayList\(Itr中的成员变量,表示对ArrayList修改次数的期望值,在循环开始的时候初始化值为modCount。ArrayList.remove()不会对expectedModCount造成变动,ArrayList\)Itr.remove()才会。

    public boolean hasNext() {
        return cursor != size;
    }
    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];
    }
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
    

    3、迭代器删除

    迭代器删除用ArrayList$Itr.remove()规避了2的问题,从而正确遍历删除元素

    List<String> list=new ArrayList<>();
    list.add("a");
    list.add("b");
    list.add("c");
    list.add("d");
    list.add("e");
    list.add("f");
    System.out.println("删除前的list:"+list.toString());
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()){
        String next = iterator.next();
        if("c".equals(next)){
            iterator.remove();
        }
    }
    System.out.println("删除后的list"+list.toString());
    
  • 相关阅读:
    个人总结08
    npm快速入门
    Activity简介
    SELinux
    正则表达式学习笔记(二)表达式的匹配原理
    git学习笔记(一)
    使用VSFTPD传输文件
    正则表达式学习笔记(一)正则表达式入门
    Linux基础(一)磁盘分区
    Shell脚本笔记(九)数组
  • 原文地址:https://www.cnblogs.com/brewin/p/15784722.html
Copyright © 2020-2023  润新知