一、什么是Iterator:

迭代器(Iterator)是一个对象,它的工作是遍历并目标序列中的对象,它提供了一种访问一个容器(container)对象中的各个元素的方法,把访问逻辑从不同类型的集合类中抽象出来,又不必暴露该对象内部细节。通过迭代器,开发人员不需要了解容器底层的结构,就可以实现对容器的遍历。由于创建迭代器的代价小,因此迭代器通常被称为轻量级的容器。

常常使用JDK提供的迭代接口进行Java集合的迭代。

        Iterator iterator = list.iterator();while(iterator.hasNext()){String string = iterator.next();//do something}
在没有迭代器时,我们都是这么进行遍历元素的,如下:

对于数组,我们是使用下标进行处理的P:

int[] arrays = new int[10];
for(int i = 0 ; i < arrays.length ; i++){int a = arrays[i];//do something}

对于ArrayList是这么处理的:

List<String> list = new ArrayList<String>();for(int i = 0 ; i < list.size() ;  i++){String string = list.get(i);//do something}

对于这两种方式,我们总是都事先知道集合的内部结构,访问代码和集合本身是紧密耦合的,无法将访问逻辑从集合类和客户端代码中分离出来。同时每一种集合对应一种遍历方法,客户端代码无法复用。 在实际应用中如何需要将上面将两个集合进行整合是相当麻烦的。所以为了解决以上问题,Iterator模式腾空出世,它总是用同一种逻辑来遍历集合。使得客户端自身不需要来维护集合的内部结构,所有的内部状态都由Iterator来维护。客户端从不直接和集合类打交道,它总是控制Iterator,向它发送"向前","向后","取当前元素"的命令,就可以间接遍历整个集合。

二、java.util.Iterator

在Java中Iterator为一个接口,它只提供了迭代了基本规则,在JDK中他是这样定义的:对 collection 进行迭代的迭代器。迭代器取代了 Java Collections Framework 中的 Enumeration。迭代器与枚举有两点不同:

1、迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的 collection 移除元素。

2、方法名称得到了改进。

其接口定义如下:

public interface Iterator {boolean hasNext();Object next();void remove();
}

Object next():返回迭代器刚越过的元素的引用,返回值是Object,需要强制转换成自己需要的类型;

boolean hasNext():判断容器内是否还有可供访问的元素;

void remove():删除迭代器刚越过的元素;

三、各个集合的Iterator的实现:

1、ArrayList的Iterator实现:

在ArrayList内部首先是定义一个内部类Itr,该内部类实现Iterator接口,如下:

private class Itr implements Iterator<E> {int cursor;       // index of next element to returnint lastRet = -1; // index of last element returned; -1 if no suchint expectedModCount = modCount;//do something
}

而ArrayList的iterator()方法实现:

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

所以通过使用ArrayList.iterator()方法返回的是Itr()内部类,所以现在我们需要关心的就是Itr()内部类的实现:

在Itr内部定义了三个int型的变量:cursor、lastRet、expectedModCount。其中cursor表示下一个元素的索引位置,lastRet表示上一个元素的索引位置。

从cursor、lastRet定义可以看出,lastRet一直比cursor少一所以hasNext()实现方法异常简单,只需要判断cursor和lastRet是否相等即可。

public boolean hasNext() {return cursor != size;
}

对于next()实现其实也是比较简单的,只要返回cursor索引位置处的元素即可,然后修改cursor、lastRet即可:

       public E next() {checkForComodification();int i = cursor;    //记录索引位置if (i >= size)    //如果获取元素大于集合元素个数,则抛出异常throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i + 1;      //cursor + 1return (E) elementData[lastRet = i];  //lastRet + 1 且返回cursor处元素}
       final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}

checkForComodification()主要用来判断集合的修改次数是否合法,即用来判断遍历过程中集合是否被修改过。modCount用于记录ArrayList集合的修改次数,初始化为0,每当集合被修改一次(结构上面的修改,内部update不算),如add、remove等方法,modCount + 1,所以如果modCount不变,则表示集合内容没有被修改。该机制主要是用于实现ArrayList集合的快速失败机制,在Java的集合中,较大一部分集合是存在快速失败机制的。所以要保证在遍历过程中不出错误,我们就应该保证在遍历过程中不会对集合产生结构上的修改(当然remove方法除外),出现了异常错误,我们就应该认真检查程序是否出错而不是catch后不做处理。

对于remove()方法的是实现,它是调用ArrayList本身的remove()方法删除lastRet位置元素,然后修改modCount即可。

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();}}

2、ListIterator:

接口Iterator在不同的子接口中会根据情况进行功能的扩展,例如针对List的迭代器ListIterator,该迭代器只能用于各种List类的访问。ListIterator可以双向移动。添加了previous()等方法。如果是List集合,想要在迭代中操作元素可以使用List集合的特有迭代器ListIterator,该迭代器支持在迭代过程中,添加元素和修改元素。

四、for循环、forEach、Iterator对比:

相同点:都是用于遍历集合元素的。

不同点:

1、形式差别:

//for循环的形式是:
for(int i=0;i<arr.size();i++){...}

//foreach的形式是:
for(int i:arr){...}

//iterator的形式是
Iterator it = arr.iterator();
while(it.hasNext()){ object o =it.next(); ...}

2、条件差别:

(1)for循环需要知道集合或数组的大小,而且需要是有序的,不然无法遍历;
(2)foreach和iterator都不需要知道集合或数组的大小,他们都是得到集合内的每个元素然后进行处理;

3、多态差别:

(1)for和foreach都需要先知道集合的类型,甚至是集合内元素的类型,即需要访问内部的成员,不能实现多态;
(2)iterator是一个接口类型,可以使用相同方式去遍历不同集合中元素,而不用考虑集合类的内部实现(只要它实现了 java.lang.Iterable 接口),而且他还能随时修改和删除集合的元素,能够将遍历序列的操作与序列底层的结构分离。迭代器统一了对容器的访问方式。这也是接口的解耦的最好体现。

例如:如果使用 Iterator 来遍历集合中元素,一旦不再使用 List 转而使用 Set 来组织数据,那遍历元素的代码不用做任何修改,如果使用 for 来遍历,那所有遍历此集合的算法都得做相应调整,因为List有序,Set无序,结构不同,他们的访问算法也不一样。

4、效率差别:

(1)采用ArrayList对随机访问比较快,而for循环中的get()方法,采用的即是随机访问的方法,因此在ArrayList里,for循环较快。

(2)采用LinkedList则是顺序访问比较快,iterator中的next()方法,采用的即是顺序访问的方法,因此在LinkedList里,使用iterator较快。

(3)从数据结构角度分析,for循环适合访问顺序结构,可以根据下标快速获取指定元素.而Iterator 适合访问链式结构,因为迭代器是通过next()和Pre()来定位的.可以访问没有顺序的集合。

5、foreach 和 iterator 的其他区别:

使用foreach循环语句的优势在于更加简洁,更不容易出错,不必关心下标的起始值和终止值,底层由iterator实现的,他们最大的不同之处就在于remove()方法上。

如果在forEach循环的过程中调用集合的remove()方法,就会导致循环出错,因为循环过程中list.size()的大小变化了,就导致了错误。 所以,如果想在循环语句中删除集合中的某个元素,就要用迭代器iterator的remove()方法,因为它的remove()方法不仅会删除元素,还会维护一个标志,用来记录目前是不是可删除状态,例如,你不能连续两次调用它的remove()方法,调用之前至少有一次next()方法的调用。

参考文章:

https://blog.csdn.net/iamkila/article/details/7266890?utm_source=blogxgwz6

https://blog.csdn.net/chenssy/article/details/37521461

Java基础篇:Iterator迭代器相关推荐

  1. Java基础篇--设计模式

    目录 前言 设计模式 创建型模式 单例模式 工厂方法模式 抽象工厂模式 建造者模式 原型模式 结构型模式 适配器模式 桥接模式 组合模式 装饰模式 外观模式 亨元模式 代理模式 行为型模式: 访问者模 ...

  2. 《Java 后端面试经》Java 基础篇

    <Java 后端面试经>专栏文章索引: <Java 后端面试经>Java 基础篇 <Java 后端面试经>Java EE 篇 <Java 后端面试经>数 ...

  3. 你所需要的java基础篇深入解析大汇总

    java基础篇深入解析大总结 java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序 ...

  4. Java基础篇4——数组

    Java基础篇4--数组 1.数组的概念 当需要在Java程序中记录单个数据内容时,则声明一个变量即可 当需要在Java程序中记录多个类型相同的数据内容时,则声明一个一维数 组即可,一维数组本质上就是 ...

  5. Java基础篇3——流程控制

    Java基础篇3--流程控制 1.顺序结构 正常代码的流程即是顺序流程 2.分支结构 2.1.if-else分支 if(条件表达式) {语句块1; } if(条件表达式) {语句块1; } else ...

  6. Java基础篇2——运算符

    Java基础篇2--运算符 1.运算符 1.1.算数运算符 +表示加法运算符 -表示减法运算符 *表示乘法运算符 /表示除法运算符 %表示取余运算符 1.2.关系运算符 所有以关系运算符作为最终运算的 ...

  7. Java基础篇1——变量与数据类型

    Java基础篇1--变量与数据类型 1.标识符命名规则 标识符以由大小写字母.数字.下划线(_)和美元符号($)组成,但是不能以数字开头. 大小写敏感 不能与Java语言的关键字重名 不能和Java类 ...

  8. 菜鸟学习笔记:Java基础篇7(包装类、时间相关类、文件类、异常处理类)

    菜鸟学习笔记:Java其他常用类 基本数据类型包装类 时间处理和文件处理相关类 Date时间类 SimpleDateFormat Calendar日历类 文件类 异常机制 异常的概念 Java异常处理 ...

  9. 菜鸟学习笔记:Java基础篇6(数组、字符串)

    菜鸟学习笔记:Java常用类(数组.字符串) 数组 概述 数组的定义 二维数组 数组查找和排序 查找 排序 数组运用--字符串 不可变字符序列(String) 可变字符序列(StringBuilder ...

  10. 菜鸟学习笔记:Java基础篇5(抽象类与接口、回调函数、内部类)

    菜鸟学习笔记:Java面向对象篇下 抽象类 接口 回调函数 内部类 成员内部类 匿名内部类 抽象类 通过前面知识的学习,抽象类这个概念应该不难理解,但比较容易和后面要说的接口混淆,而且在面试中也比较爱 ...

最新文章

  1. (转)Activity的四种launchMode
  2. C语言入门书籍--C语言程序设计
  3. UA MATH566 统计理论7 还有一个例子:推导卡方检验
  4. C++ Primer 5th笔记(9)chapter9 顺序容器 vector 容器的自增长 容器适配器
  5. Nginx四层负载均衡模块添加
  6. 弱,弱,最弱,利用专业参考来利用垃圾收集器
  7. An Algorithm Summary of Programming Collective Intelligence (1)
  8. mac连续互通相机功能小技巧
  9. 淘宝客APP源码 社交电商uniapp开发源码 前端源码自营商城
  10. 课程作业记录10:63位PN码序列扩频通信Matlab仿真
  11. 卡巴斯基7.0离线更新升级包病毒库
  12. 实验二木马分析(控制分析)实验和实验三冰河木马实验
  13. Windows开启winrm
  14. 【HDU4622】Reincarnation
  15. 人工智能—— 产生式表示法
  16. Selig集团宣布收购MGJ,成为今年公布的第二笔收购
  17. 《激活个体》读书笔记
  18. 基于pixhawk2.4.6硬件和ChibiOS系统的ardupilot启动流程:从上电到ArduCopter应用层代码
  19. 稻城亚丁徒步攻略,与你共同感受这片净土
  20. Android SurfaceFlinger SW Vsync模型

热门文章

  1. 【数据分析实例】1000 万条淘宝用户行为数据实时分析
  2. 四十五、爬取QQ音乐Lemon 日语歌的评论
  3. keras从入门到放弃(七)多层感知器训练
  4. 复旦大学张奇组:对话摘要数据不足?对话数据、文档摘要数据,我全都要!...
  5. 零基础如何快速上手高精度AI模型开发?
  6. Russell大师课+大厂专家倾授+5小时黑客松,上海临港人工智能开发者大会倒计时5天...
  7. 8天 = 4万元奖金 + CNCC参会资助 | 2019科研文本理解比赛
  8. 语言中拟合函数 计算aic_Go语言函数深度解析(中)
  9. html5option的js代码,ng-option(示例代码)
  10. js文件中加载其他js文件