java开发——增强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。最后一个都删除了,哪里还有下一个,理所当然要抛异常了!

觉得有用的老铁给我博客赞一下呗! 

发布了78 篇原创文章 · 获赞 131 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/river66/article/details/88873872
今日推荐