循环删除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());
posted @ 2022-01-10 15:50  之石先生  阅读(488)  评论(0编辑  收藏  举报