每个实现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异常了

ArrayList中的Iterator详解的更多相关文章

  1. [转载]Java迭代器(iterator详解以及和for循环的区别)

    Java迭代器(iterator详解以及和for循环的区别) 觉得有用的话,欢迎一起讨论相互学习~[Follow] 转载自 https://blog.csdn.net/Jae_Wang/article ...

  2. C++中的STL中map用法详解(转)

    原文地址: https://www.cnblogs.com/fnlingnzb-learner/p/5833051.html C++中的STL中map用法详解   Map是STL的一个关联容器,它提供 ...

  3. [转载]java中import作用详解

    [转载]java中import作用详解 来源: https://blog.csdn.net/qq_25665807/article/details/74747868 这篇博客讲的真的很清楚,这个作者很 ...

  4. php中关于引用(&)详解

    php中关于引用(&)详解 php的引用(就是在变量或者函数.对象等前面加上&符号) 在PHP 中引用的意思是:不同的变量名访问同一个变量内容. 与C语言中的指针是有差别的.C语言中的 ...

  5. JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解

    二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ...

  6. AngularJS select中ngOptions用法详解

    AngularJS select中ngOptions用法详解   一.用法 ngOption针对不同类型的数据源有不同的用法,主要体现在数组和对象上. 数组: label for value in a ...

  7. 【转载】C/C++中extern关键字详解

    1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...

  8. oracle中imp命令详解 .

    转自http://www.cnblogs.com/songdavid/articles/2435439.html oracle中imp命令详解 Oracle的导入实用程序(Import utility ...

  9. Android中Service(服务)详解

    http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...

随机推荐

  1. 当微信小程序遇上filter~

    在微信小程序的开发过程中,当你想要实现不同页面间的数据绑定,却为此抓耳饶腮时,不妨让微信小程序与filter 来一场完美的邂逅,相信会给你带来别样的惊喜~ 前段时间被安利了一个很实用的公众号-前端早读 ...

  2. Css里的BFC

    一.BFC简介 BFC全称:Block Formatting Contexts (BFC,块级格式化上下文),就是 一个块级元素 的渲染显示规则 (可以把 BFC 理解为一个封闭的大箱子,,容器里面的 ...

  3. JZOJ 3928. 【NOIP2014模拟11.6】射击

    3928. [NOIP2014模拟11.6]射击 (Standard IO) Time Limits: 1000 ms Memory Limits: 65536 KB Description 有问题, ...

  4. python正则表达式之re模块方法介绍

    python正则表达式之re模块其他方法 1:search(pattern,string,flags=0) 在一个字符串中查找匹配 2:findall(pattern,string,flags=0) ...

  5. ReentrantLock 源码分析以及 AQS (一)

    前言 JDK1.5 之后发布了JUC(java.util.concurrent),用于解决多线程并发问题.AQS 是一个特别重要的同步框架,很多同步类都借助于 AQS 实现了对线程同步状态的管理. A ...

  6. openwrt sdk 添加软件包 Makefile 写法

    参考 https://openwrt.org/start?id=docs/guide-developer/packages ,英文稍好点的自己看吧,我写出来也就是方便,英文不好的人看. 软件包的来源, ...

  7. update join和delete join

    UPDATE ASET A.A2 = B.B2FROM BINNER JOIN AON A.A1 = B.B1WHERE B.B2 = "XXX" 上面的语句在SQL SERVER ...

  8. CSS 文本截断方案

    单行截断 .ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } 此方法兼容到ie6过.不过只能单行 ...

  9. 树莓派上搭建唤醒词检测引擎 Snowboy

    Snowboy 是一款高度可定制的唤醒词检测引擎,可以用于实时嵌入式系统,并且始终监听(即使离线).当前,它可以运行在 Raspberry Pi.(Ubuntu)Linux 和 Mac OS X 系统 ...

  10. Java反射之Class类

    接下来的几章,我们谈一谈java的反射机制. 反射就是从一个java类中映射出一个java类或是一个实例.通常在很多框架中都用到反射,比如常用的ssm框架,在配置文件中总是会写到类的全名,框架通过读取 ...