当前位置: 首页 > news >正文

052_迭代器(Iterator / ListIterator)

一、迭代器概述

迭代器(Iterator)是 Java 集合框架中用于遍历集合元素的工具接口,它提供了一种统一的遍历方式,屏蔽了不同集合底层数据结构的差异(如数组、链表、哈希表等)。其核心思想是 “迭代器负责遍历,集合负责存储”,通过迭代器可以安全、高效地访问集合中的元素。

Java 中主要的迭代器接口包括:

  • Iterator:基础迭代器,支持单向遍历和元素删除。
  • ListIterator:Iterator的子接口,仅适用于List集合,支持双向遍历、元素添加和修改。

迭代器解决了传统for循环遍历的两个核心问题:

  • 避免暴露集合底层实现(无需通过索引访问,适配所有集合类型)。
  • 提供遍历过程中的元素修改安全性(通过迭代器自身的remove()方法,避免并发修改异常)。

在这里插入图片描述

二、Iterator 详解

2.1 核心定义与作用

Iterator是所有迭代器的基础接口,定义在java.util包中,仅支持单向遍历(从集合头部到尾部),适用于所有Collection接口的实现类(如List、Set、Queue等)。

通过集合的iterator()方法可获取迭代器实例,核心流程为:

  1. 调用hasNext()判断是否有下一个元素。
  2. 调用next()获取下一个元素(并移动迭代器指针)。
  3. (可选)调用remove()删除当前元素(需在next()之后调用)。

2.2 核心方法

方法定义功能说明
boolean hasNext()判断集合中是否还有未遍历的元素,有则返回true,否则返回false。
E next()返回集合中的下一个元素,并将迭代器指针向后移动一位。若没有下一个元素,抛出NoSuchElementException。
void remove()删除next()方法最后返回的元素(需在next()之后调用,否则抛出IllegalStateException)。

2.3 使用示例

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class IteratorDemo {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("Apple");list.add("Banana");list.add("Cherry");// 获取迭代器Iterator<String> iterator = list.iterator();// 遍历集合while (iterator.hasNext()) {String element = iterator.next(); // 获取下一个元素System.out.println(element);// 示例:删除"Banana"if ("Banana".equals(element)) {iterator.remove(); // 仅能通过迭代器删除,避免并发修改异常}}System.out.println("删除后集合:" + list); // 输出:[Apple, Cherry]}
}

2.4 核心特点

特点说明
单向遍历仅支持从集合头部到尾部的顺序遍历(hasNext()+next()),无法向前遍历。
通用性适用于所有Collection实现类(List、Set、Queue等),兼容性强。
元素删除支持通过remove()方法删除当前元素,但需在next()之后调用(依赖next()记录当前元素位置)。
并发安全遍历过程中通过迭代器的remove()修改集合,不会触发ConcurrentModificationException(直接修改集合会报错)。
无添加 / 修改能力仅能遍历和删除元素,无法向集合中添加或修改元素。

在这里插入图片描述

三、ListIterator 详解

3.1 核心定义与作用

ListIterator是Iterator的子接口,仅适用于List接口的实现类(如ArrayList、LinkedList等),扩展了Iterator的功能,支持双向遍历元素添加 / 修改,是List集合特有的迭代器。

通过List的listIterator()方法可获取实例,若传入索引参数(如listIterator(int index)),迭代器指针会从指定索引位置开始遍历,进一步增强了遍历的灵活性。

3.2 核心方法(扩展自 Iterator)

方法定义功能说明
boolean hasPrevious()判断集合中是否有上一个未遍历的元素(向前遍历),有则返回true。
E previous()返回集合中的上一个元素,并将迭代器指针向前移动一位。若没有上一个元素,抛出NoSuchElementException。
void add(E e)在当前指针位置插入元素(插入后元素位于next()返回元素之前,previous()返回元素之后)。
void set(E e)修改next()或previous()方法最后返回的元素(需在next()/previous()之后调用)。
int nextIndex()返回下一个元素的索引(若没有下一个元素,返回集合大小)。
int previousIndex()返回上一个元素的索引(若没有上一个元素,返回-1)。

3.3 使用示例

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;public class ListIteratorDemo {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("A");list.add("B");list.add("C");// 获取ListIterator(从索引1开始遍历)ListIterator<String> lit = list.listIterator(1);System.out.println("向后遍历:");while (lit.hasNext()) {int index = lit.nextIndex(); // 获取下一个元素索引String element = lit.next();System.out.println("索引" + index + ":" + element); // 输出:索引1:B,索引2:C}System.out.println("向前遍历:");while (lit.hasPrevious()) {int index = lit.previousIndex(); // 获取上一个元素索引String element = lit.previous();System.out.println("索引" + index + ":" + element); // 输出:索引1:B,索引0:A}// 在当前位置(索引0后)插入元素lit.add("D");System.out.println("插入后集合:" + list); // 输出:[A, D, B, C]// 修改下一个元素(当前指针指向索引1的"D")lit.next(); // 移动到"D"lit.set("D-Updated");System.out.println("修改后集合:" + list); // 输出:[A, D-Updated, B, C]}
}

3.4 核心特点

特点说明
双向遍历支持向前(hasPrevious()+previous())和向后(hasNext()+next())遍历,灵活性更高。
元素操作扩展除删除外,支持add()插入元素和set()修改元素,丰富了集合的修改方式。
索引定位可通过nextIndex()/previousIndex()获取当前指针位置索引,便于精准操作。
起始位置可控支持从指定索引开始遍历(listIterator(int index)),无需从头遍历。
仅适用于 List依赖List的索引特性,无法用于Set、Queue等非 List 集合。

在这里插入图片描述

四、Iterator 与 ListIterator 对比

维度IteratorListIterator
继承关系顶层接口,无父接口继承Iterator接口,是子接口
适用集合所有Collection实现类(List、Set、Queue等)仅List实现类(ArrayList、LinkedList等)
遍历方向单向(仅向后:hasNext()+next())双向(向后 + 向前:hasNext()/hasPrevious())
核心操作遍历(hasNext()/next())、删除(remove())遍历、删除、添加(add())、修改(set())
索引支持无索引相关方法有nextIndex()/previousIndex()获取索引
起始位置控制仅能从集合头部开始遍历可通过listIterator(int index)指定起始索引
并发修改安全性支持通过remove()安全删除支持remove()/add()/set()安全修改

5.1 并发修改异常(ConcurrentModificationException)

遍历过程中若直接通过集合的方法(如add()、remove())修改集合结构,迭代器会检测到并发修改,抛出ConcurrentModificationException。正确做法是通过迭代器自身的方法修改集合

  • Iterator:仅能通过remove()删除元素。
  • ListIterator:可通过remove()/add()/set()修改元素。

错误示例(直接修改集合)

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
Iterator<String> it = list.iterator();while (it.hasNext()) {String elem = it.next();if ("B".equals(elem)) {list.remove(elem); // 直接调用集合的remove(),抛出异常}
}

正确示例(通过迭代器修改)

// 使用Iterator的remove()
while (it.hasNext()) {String elem = it.next();if ("B".equals(elem)) {it.remove(); // 迭代器删除,安全无异常}
}// 使用ListIterator的add()
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {if ("C".equals(lit.next())) {lit.add("D"); // 迭代器添加,安全无异常}
}

5.2 迭代器状态依赖

  • Iterator的remove()必须在next()之后调用(需先通过next()获取元素,迭代器记录当前元素位置),否则抛出IllegalStateException。
  • ListIterator的set()必须在next()或previous()之后调用(需先获取待修改元素),add()无此限制,但add()后调用remove()会报错(add()插入的元素未被next()/previous()记录)。

5.3 性能考量

  • Iterator遍历Set集合时性能最优(无需索引支持)。
  • ListIterator在LinkedList中双向遍历性能优于通过索引遍历(避免LinkedList索引访问的O(n)开销)。

六、适用场景总结

场景需求推荐迭代器原因分析
遍历Set或Queue集合Iterator这些集合无索引,Iterator是唯一通用遍历方式。
单向遍历List集合,仅需读取Iterator功能足够,无需额外扩展,性能略优。
双向遍历List集合ListIterator支持向前 / 向后遍历,满足复杂遍历需求(如从中间位置开始遍历)。
遍历List时需插入 / 修改元素ListIterator提供add()/set()方法,是List集合修改元素的安全方式。
多线程环境下遍历集合Iterator/ListIterator迭代器自身的修改方法(remove()/add())可避免并发修改异常。

七、总结

迭代器是 Java 集合遍历的核心工具,Iterator提供了基础的单向遍历和删除能力,适用于所有集合;ListIterator作为List特有的迭代器,扩展了双向遍历和元素添加 / 修改功能,灵活性更强。

使用时需根据集合类型和需求选择合适的迭代器:通用场景选Iterator,List的复杂遍历和修改场景选ListIterator。同时需注意遍历过程中通过迭代器自身方法修改集合,避免并发修改异常,确保遍历的安全性和高效性。

掌握迭代器的使用不仅能统一集合遍历方式,更能深入理解 Java 集合框架的设计思想 ——“接口抽象,实现分离”,提升代码的通用性和可维护性。

http://www.dtcms.com/a/290902.html

相关文章:

  • HCL 三层知识总结
  • Java 二叉树
  • uniapp+vue3预约时间和日期
  • registry-ui docker搭建私有仓库的一些问题笔记
  • 在React中做过哪些性能优化?
  • java每日精进 7.21【Uel表达式和流程设计】
  • 【Elasticsearch】IndexModule
  • 【沧海拾昧】微分先行PID与中间微分反馈控制
  • 工业网关的应用场景
  • 【正常配置了beast扩展,phpinfo信息也显示了,但是就是不运行】
  • 前端-DOM
  • pandas 的series和dataframe的用法,六个题目
  • 141、环形链表
  • 前后端分离项目进阶1---后端
  • 果园里的温柔之手:Deepoc具身智能如何重塑采摘机器人的“生命感知”
  • Python day20 - 特征降维之奇异值分解
  • 【设计模式C#】工厂方法模式(相比简单工厂模式更加具有灵活性和扩展性的工厂模式)
  • git_guide
  • prometheus主动服务发现机制
  • 在 React 中实现全局防复制hooks
  • Java 解析前端上传 ZIP 压缩包内 Excel 文件的完整实现方案
  • Neo4j 5.x版本的导出与导入数据库
  • 易语言+懒人精灵/按键中控群控教程(手机、主板机、模拟器通用)
  • CFD总压边界条件的理解与开发处理
  • DM8数据库Docker镜像部署最佳实践
  • 自学鸿蒙测试day01-插件安装推荐
  • Vue 3 响应式原理详细解读【一】—— Proxy 如何突破 defineProperty 的局限
  • 计算机发展史:晶体管时代的技术飞跃
  • Boost库智能指针boost::shared_ptr详解和常用场景使用错误示例以及解决方法
  • 软件测试 —— A / 入门