在Iterator迭代器中使用iterator的remove方法和集合本身的remove方法删除集合中某个数据的区别

在迭代循环遍历时删除某个数据,发现以下两种现象:使用集合本身的remove方法会报错,而使用iterator迭代器的remove方法不会出错;

使用集合本身的remove方法:

public class MyList {
    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");
        Iterator<String> iterator=list.iterator();
        while(iterator.hasNext()){
            String item=iterator.next();
            if(item.equals("B")){
                list.remove(item);
            }
            System.out.println(item);
        }
    }
}

使用list.remove(),会报一个java.util.ConcurrentModificationException的异常错误:
在这里插入图片描述
使用迭代器的remove方法:

public class MyList {
    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");
        Iterator<String> iterator=list.iterator();
        while(iterator.hasNext()){
            String item=iterator.next();
            if(item.equals("B")){
                //list.remove(item);
                iterator.remove();
            }
            System.out.println(item);
        }
         System.out.println(list);
    }
}

使用iterator.remove()不会出错;

通过观察源码可知:

在AbstractList的源码中:每一次对集合进行add、set、get、remove操作都会进行一次checkForComodification();校验操作:

public E set(int index, E element) {
        rangeCheck(index);
        checkForComodification();
        return l.set(index+offset, element);
    }

    public E get(int index) {
        rangeCheck(index);
        checkForComodification();
        return l.get(index+offset);
    }

    public int size() {
        checkForComodification();
        return size;
    }

    public void add(int index, E element) {
        rangeCheckForAdd(index);
        checkForComodification();
        l.add(index+offset, element);
        this.modCount = l.modCount;
        size++;
    }

    public E remove(int index) {
        rangeCheck(index);
        checkForComodification();
        E result = l.remove(index+offset);
        this.modCount = l.modCount;
        size--;
        return result;
    }

而checkForComodification()方法中的操作是:

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

那modCount和expectedModCount是什么呢?

在ArrayList的源码中可以发现:
在ArrayList中每进行一次remove、add操作,modCount都会加1:

由此可以猜测modCount是保存对集合进行的操作次数的变量;

在迭代器Iterator中,

  private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;//先将modCount赋值给expectedModCount,保存对集合的操作次数
         Itr() {}

        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;//在此处更新了expectedModCount,所以不会出错
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

可以发现,modCount存在于AbstractList中,记录集合被修改(add、remove)的次数;在迭代器中,进行list.iterator()时,首先会将修改次数modCount赋值给迭代器中的expectedModCount,用expectedModCount来存储当前集合修改次数;

而如果在迭代循环的过程中:
如果使用了list.remove方法,就会将modCount+1,而后再进行checkForComodification()方法时,就会发现modCount与expectedModCount不相等,就会抛出异常 ConcurrentModificationException;

如果使用了Iterator的remove方法,在Iterator的remove方法中可以发现,它将expectedModCount进行了更新: expectedModCount = modCount;expectedModCount 与modCount相等,就不会报错了;

可以说,迭代器就是当前集合的一个副本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值