每个实现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. 基于JS正则实现模板数据动态渲染

    最近业务上需要动态渲染模板数据: 一.业务需求: 1.前端后端定义好模板以及变量名,根据打印机类型转换成对应sdk需要的标签模板,保存数据库 2.订单数据是前端根据支付结果获取的,最终渲染完的数据模板 ...

  2. Python中的BeautifulSoup库简要总结

    一.基本元素 BeautifulSoup库是解析.遍历.维护“标签树”的功能库. 引用 from bs4 import BeautifulSoup import bs4 html文档-标签树-Beau ...

  3. htm5新特性(转)

    转自:http://hyuhan.com/2017/07/06/... 今天来谈谈前端面试中基本上每次一面都会被问到的一个问题,那就是html5的新特性了.这个是学习前端必须掌握的基础知识. 新增的元 ...

  4. java线程组

    1 简介 一个线程集合.是为了更方便地管理线程.父子结构的,一个线程组可以集成其他线程组,同时也可以拥有其他子线程组. 从结构上看,线程组是一个树形结构,每个线程都隶属于一个线程组,线程组又有父线程组 ...

  5. Chromium的无锁线程模型C++代码示例

    引言 作者:程序员bingo,主要关注客户端架构设计.性能优化.崩溃处理,有多年的Chromium浏览器开发经验. 多线程一直是软件开发中最容易出问题的环节,很多的崩溃.卡死问题都与多线程有关.在常用 ...

  6. 02 JPA

    JPA概述 JPA的全称是Java Persistence API, 即Java 持久化API,是SUN公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象类构成.       JPA通过JDK ...

  7. 【Spring Data 系列学习】Spring Data JPA @Query 注解查询

    [Spring Data 系列学习]Spring Data JPA @Query 注解查询 前面的章节讲述了 Spring Data Jpa 通过声明式对数据库进行操作,上手速度快简单易操作.但同时 ...

  8. Google Flutter Clock 大赛优秀项目推荐

    Flutter 在 Google 加持下,如今可以作为跨平台首选了.早在 Flutter 刚刚出现强势苗头,我作为第一批体验了一把,<Flutter 初尝:从 Java 无缝过渡>,不过也 ...

  9. C# 时间戳(TimeStamp)与时间(DateTime)的互相转换

    什么是时间戳:时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数. 时间戳在线转换网址:https://tool.lu/ ...

  10. Python3 + requests + unittest接口测试

    一.缘 起 笔者最近完成了基于Python3 + requests + unittest的接口测试脚本,故在此做一下记录,于己为复盘,于彼为学习和参考 二.思 路 接口测试无非三步: 首先,造数据 - ...