首页 Java java教程 Java集合Iterator迭代的实现方法

Java集合Iterator迭代的实现方法

Jan 23, 2017 pm 05:00 PM

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

Iterator iterator = list.iterator();
while(iterator.hasNext()){
String string = iterator.next();
//do something
}
登录后复制

迭代其实我们可以简单地理解为遍历,是一个标准化遍历各类容器里面的所有对象的方法类,它是一个很典型的设计模式。Iterator 模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。 在没有迭代器时我们都是这么进行处理的。如下:

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

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,向它发送”向前”,”向后”,”取当前元素”的命令,就可以间接遍历整个集合。

上面只是对 Iterator 模式进行简单的说明,下面我们看看 Java 中 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():删除迭代器刚越过的元素

对于我们而言,我们只一般只需使用 next()、hasNext() 两个方法即可完成迭代。如下:

for(Iterator it = c.iterator(); it.hasNext(); ) {
  Object o = it.next();
   //do something
}
登录后复制

前面阐述了 Iterator 有一个很大的优点,就是我们不必知道集合的内部结果,集合的内部结构、状态由 Iterator 来维持,通过统一的方法 hasNext()、next() 来判断、获取下一个元素,至于具体的内部实现我们就不用关心了。但是作为一个合格的程序员我们非常有必要来弄清楚 Iterator 的实现。下面就 ArrayList 的源码进行分析分析。

二、各个集合的 Iterator 的实现

下面就 ArrayList 的 Iterator 实现来分析,其实如果我们理解了 ArrayList、Hashset、TreeSet 的数据结构,内部实现,对于他们是如何实现 Iterator 也会胸有成竹的。因为 ArrayList 的内部实现采用数组,所以我们只需要记录相应位置的索引即可,其方法的实现比较简单。

2.1、ArrayList 的 Iterator 实现

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

private class Itr implements Iterator<E> {
//do something
}
登录后复制

而 ArrayList 的 iterator() 方法实现:

public Iterator<E> iterator() {
return new Itr();
}
登录后复制

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

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

int cursor;
int lastRet = -1;
int expectedModCount = modCount;
登录后复制

从 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 + 1
return (E) elementData[lastRet = i]; //lastRet + 1 且返回cursor处元素
}
登录后复制

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

final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
登录后复制

对于 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();
}
}
登录后复制

以上所述是小编给大家介绍的Java集合Iterator迭代的实现方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对PHP中文网的支持!

更多Java集合Iterator迭代的实现方法相关文章请关注PHP中文网!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

公司安全软件导致应用无法运行?如何排查和解决? 公司安全软件导致应用无法运行?如何排查和解决? Apr 19, 2025 pm 04:51 PM

公司安全软件导致部分应用无法正常运行的排查与解决方法许多公司为了保障内部网络安全,会部署安全软件。...

如何使用MapStruct简化系统对接中的字段映射问题? 如何使用MapStruct简化系统对接中的字段映射问题? Apr 19, 2025 pm 06:21 PM

系统对接中的字段映射处理在进行系统对接时,常常会遇到一个棘手的问题:如何将A系统的接口字段有效地映�...

如何优雅地获取实体类变量名构建数据库查询条件? 如何优雅地获取实体类变量名构建数据库查询条件? Apr 19, 2025 pm 11:42 PM

在使用MyBatis-Plus或其他ORM框架进行数据库操作时,经常需要根据实体类的属性名构造查询条件。如果每次都手动...

如何将姓名转换为数字以实现排序并保持群组中的一致性? 如何将姓名转换为数字以实现排序并保持群组中的一致性? Apr 19, 2025 pm 11:30 PM

将姓名转换为数字以实现排序的解决方案在许多应用场景中,用户可能需要在群组中进行排序,尤其是在一个用...

IntelliJ IDEA是如何在不输出日志的情况下识别Spring Boot项目的端口号的? IntelliJ IDEA是如何在不输出日志的情况下识别Spring Boot项目的端口号的? Apr 19, 2025 pm 11:45 PM

在使用IntelliJIDEAUltimate版本启动Spring...

Java对象如何安全地转换为数组? Java对象如何安全地转换为数组? Apr 19, 2025 pm 11:33 PM

Java对象与数组的转换:深入探讨强制类型转换的风险与正确方法很多Java初学者会遇到将一个对象转换成数组的�...

电商平台SKU和SPU数据库设计:如何兼顾用户自定义属性和无属性商品? 电商平台SKU和SPU数据库设计:如何兼顾用户自定义属性和无属性商品? Apr 19, 2025 pm 11:27 PM

电商平台SKU和SPU表设计详解本文将探讨电商平台中SKU和SPU的数据库设计问题,特别是如何处理用户自定义销售属...

使用TKMyBatis进行数据库查询时,如何优雅地获取实体类变量名构建查询条件? 使用TKMyBatis进行数据库查询时,如何优雅地获取实体类变量名构建查询条件? Apr 19, 2025 pm 09:51 PM

在使用TKMyBatis进行数据库查询时,如何优雅地获取实体类变量名以构建查询条件,是一个常见的难题。本文将针...

See all articles