使用增强for遍历集合时,删除元素是如何抛出异常的?

看如下代码:

    public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
     
            for (String name : list) {
                System.out.println(name);
                if ("ccc".equals(name)) {
                    list.remove(name);
                }
            }
        }

看一下抛出的异常信息:

remove()方法并不会抛出异常,抛出异常的是Itr的next方法!!但是remove()方法会导致Itr.next()发生异常。

 Itr是ArrayList的一个内部迭代器类,增强for实际上调用的就是这个迭代器的代码!看下这两个方法的代码:

    public boolean remove(Object o) {
           modCount++;//就是这个变量(修改次数)和异常的发生有密切关系!!
           ...
    }

再看下Itr的代码:

    private class Itr implements Iterator<E> {
            int expectedModCount = modCount;//这里是初始化赋值
     
            Itr() {}
     
            public E next() {
                checkForComodification();
                ...
            }
            final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }
     
    }

当使用增强for遍历时,会new Itr(),在初始化对象的时候expectedModCount就已经被modCount初始化确定了!!所以调用了remove()方法会使modCount++。导致expectedModCount、modCount不相等!这样再取下一个元素next()的时候,就会被检查出不相等,导致程序抛出ConcurrentModificationException异常。

补充:

1、我们直接使用ArrayList的迭代器,其实用的也是Itr类对象。所以直接用增强for会更方便!

    Iterator<String> iterator = list.iterator();
     
    public Iterator<E> iterator() {
            return new Itr();
    }

2、使用增强for遍历时,删除list中的倒数第二个元素,不会抛出ConcurrentModificationException异常。

            List<String> list = new ArrayList<>();
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
     
            for (String name : list) {
                System.out.println(name);
                if ("bbb".equals(name)) {
                    list.remove(name);
                }
            }
            for(String name:list){
                System.out.println(name);
            }

正常运行!打印:

aaa
bbb
aaa
ccc

原因:

 remove("bb");以后,程序认为已经遍历完成,hasNext()返回false,所以不会再执行next()去取得下一个元素"cc"。所以不会检查expectedModCount、modCount是否相等,故不会抛出异常。

上面的增强for的使用,相当于下面迭代器的使用:

            Iterator<String> iterator = list.iterator();
            while (iterator.hasNext()){
                String name = iterator.next();
                System.out.println(name);
                if("bbb".equals(name)){
                    list.remove(name);
                }
            }

 下面看下为什么删除了倒数第二个元素后hasNext()会返回false,删除最后一个元素后hasNext却返回true!

    public E remove(Object o) {
            ...
            elementData[--size] = null; // clear to let GC do its work
            ...
    }
     
    public boolean hasNext() {
           //cursor是当前元素的index
          return cursor != size;
    }

 不难发现,remove(倒是第二个);的时候,--size导致cursor和size相等,所以hasNext会返回false。而remove(最后一个);会导致cursor比size大1,所以cursor!=size会返回true,即hasNext返回true。最后一个都删除了,哪里还有下一个,理所当然要抛异常了!

仅学习使用
原文作者:

看如下代码:

    public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
     
            for (String name : list) {
                System.out.println(name);
                if ("ccc".equals(name)) {
                    list.remove(name);
                }
            }
        }

看一下抛出的异常信息:

remove()方法并不会抛出异常,抛出异常的是Itr的next方法!!但是remove()方法会导致Itr.next()发生异常。

 Itr是ArrayList的一个内部迭代器类,增强for实际上调用的就是这个迭代器的代码!看下这两个方法的代码:

    public boolean remove(Object o) {
           modCount++;//就是这个变量(修改次数)和异常的发生有密切关系!!
           ...
    }

再看下Itr的代码:

    private class Itr implements Iterator<E> {
            int expectedModCount = modCount;//这里是初始化赋值
     
            Itr() {}
     
            public E next() {
                checkForComodification();
                ...
            }
            final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }
     
    }

当使用增强for遍历时,会new Itr(),在初始化对象的时候expectedModCount就已经被modCount初始化确定了!!所以调用了remove()方法会使modCount++。导致expectedModCount、modCount不相等!这样再取下一个元素next()的时候,就会被检查出不相等,导致程序抛出ConcurrentModificationException异常。

补充:

1、我们直接使用ArrayList的迭代器,其实用的也是Itr类对象。所以直接用增强for会更方便!

    Iterator<String> iterator = list.iterator();
     
    public Iterator<E> iterator() {
            return new Itr();
    }

2、使用增强for遍历时,删除list中的倒数第二个元素,不会抛出ConcurrentModificationException异常。

            List<String> list = new ArrayList<>();
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
     
            for (String name : list) {
                System.out.println(name);
                if ("bbb".equals(name)) {
                    list.remove(name);
                }
            }
            for(String name:list){
                System.out.println(name);
            }

正常运行!打印:

aaa
bbb
aaa
ccc

原因:

 remove("bb");以后,程序认为已经遍历完成,hasNext()返回false,所以不会再执行next()去取得下一个元素"cc"。所以不会检查expectedModCount、modCount是否相等,故不会抛出异常。

上面的增强for的使用,相当于下面迭代器的使用:

            Iterator<String> iterator = list.iterator();
            while (iterator.hasNext()){
                String name = iterator.next();
                System.out.println(name);
                if("bbb".equals(name)){
                    list.remove(name);
                }
            }

 下面看下为什么删除了倒数第二个元素后hasNext()会返回false,删除最后一个元素后hasNext却返回true!

    public E remove(Object o) {
            ...
            elementData[--size] = null; // clear to let GC do its work
            ...
    }
     
    public boolean hasNext() {
           //cursor是当前元素的index
          return cursor != size;
    }

 不难发现,remove(倒是第二个);的时候,--size导致cursor和size相等,所以hasNext会返回false。而remove(最后一个);会导致cursor比size大1,所以cursor!=size会返回true,即hasNext返回true。最后一个都删除了,哪里还有下一个,理所当然要抛异常了!

注:本文为转载博文,仅供个人学习使用


原文作者:写代码砌砖头

原文链接:https://blog.csdn.net/river66/article/details/88873872

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值