zoukankan      html  css  js  c++  java
  • ArrayList中的Iterator详解

    每个实现Iterable接口的类必须提供一个iterator方法,返回一个Iterator对象,ArrayList也不例外

    public Iterator<E> iterator() {
            return new Itr();
    }
    

    返回的是一个Itr类的对象,接下来我们来看它的部分源码

    protected transient int modCount = 0;
    
    private class Itr implements Iterator<E> {
    
    		// 指向下一个要被迭代的元素
            int cursor;       
            // 指向当前元素
            int lastRet = -1; 
            // 将modCount赋值给expectedModCount 
            int expectedModCount = modCount;
            
    

    这里主要先看一下一个重点,modCount

    modCount顾名思义就是修改次数,每次对ArrayList内容的修改都将增加这个值

    Fail-Fast 机制
    modCount主要是为了防止在迭代过程中通过List的方法(非迭代器)改变了原集合,导致出现不可预料的情况,从而提前抛出并发修改异常,注意是“提前“,这可能也是Fail-Fast机制命名的由来。在可能出现错误的情况下提前抛出异常终止操作,如下:

    ArrayList<Integer> arrayList = new ArrayList<>();
            for (int i = 0; i < 1000; i++) {
                arrayList.add(i);
    }
    
    Iterator iterator = arrayList.iterator();
    
    while (iterator.hasNext()) {
        arrayList.remove(1);
        iterator.next();
    }
    

    这段代码最终会抛出ConcurrentModificationException
    原因是因为,在迭代器进行遍历的时候,如果 iterator.next()选择了需要遍历的下一个目标时(假设这个目标为坐标3的数),

    我却调用了arrayList.remove(1)将坐标1给删了,那么这时候它就会遍历成原本坐标为4的数字4,却没有遍历数字3了,如果是LinkedList,会直接找不到目标

    为了防止这种情况,在迭代器初始化过程中会将modCount赋给迭代器的 expectedModCount。在迭代过程中,判断 modCount 跟 expectedModCount 是否相等,如果不相等就表示通过其他方法修改了 ArrayList的结构

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

    为什么说是其他方法呢?因为Iterator的remove方法和ArrayList的不一样

    public void remove() {
                if (lastRet < 0)
                    throw new IllegalStateException();
                checkForComodification();
    
                try {
                    ArrayList.this.remove(lastRet);
                    cursor = lastRet;
                    lastRet = -1;
                    expectedModCount = modCount;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
    }
    

    它在每一次删除之后都会将cursor(下一项)的位置设置为当前位置,也就是将cursor往前移动了一位,之后再将modCount赋值给expectedModCount使它们保持相等。


    这样就不会产生ConcurrentModificationException异常了

  • 相关阅读:
    springmvc log4j 配置
    intellij idea maven springmvc 环境搭建
    spring,property not found on type
    intellij idea maven 工程生成可执行的jar
    device eth0 does not seem to be present, delaying initialization
    macos ssh host配置及免密登陆
    centos7 搭建 docker 环境
    通过rest接口获取自增id (twitter snowflake算法)
    微信小程序开发体验
    gitbook 制作 beego 参考手册
  • 原文地址:https://www.cnblogs.com/fatmanhappycode/p/12231197.html
Copyright © 2011-2022 走看看