java基础 迭代Iterable接口以及迭代器Iterator

news2025/4/18 6:16:45

Itera迭代

  • Iterable < T>迭代接口
    • (1) Iterator iterator()
    • (2) forEach(Consumer<? super T> action)
      • forEach结合Consumer常见场景
      • forEach使用注意细节
    • (3)Spliterator spliterator()
  • Iterator< T>迭代器接口
    • 如何“接收” Iterator<T>
    • 核心方法
    • 迭代器的使用场景
    • 注意事项
  • 总结

在 Java 中, Iterable < T> 是一个核心接口,用于表示一个对象可以被 迭代(遍历),它定义了如何通过 迭代器(Iterator< T>)访问其元素,并支持增强的 for-each 循环

Iterable < T>迭代接口

public interface Iterable<T> {
    Iterator<T> iterator(); // 必须实现的方法

    // Java 8 新增的默认方法
    default void forEach(Consumer<? super T> action) { /* ... */ }

    // Java 8 新增的默认方法
    default Spliterator<T> spliterator() { /* ... */ }
}

(1) Iterator iterator()

作用:返回一个迭代器(Iterator< T>),用于遍历集合中的元素或进行删除元素操作。
实现要求:每个 Iterable 实现类必须提供该方法,返回一个新的迭代器实例

(2) forEach(Consumer<? super T> action)

作用:对集合中的每个非空元素进行遍历

	// 下界通配符 <? super T> 表示“T 或 T 的父类”
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

首先,这段代码里的forEach方法接受一个Consumer(消费者)参数,Consumer是一个函数式接口,接受一个输入参数并且不返回结果,accept方法为void
其次,这里用了泛型通配符<? super T>,表示Consumer可以处理T类型及其父类,比如有一个Animal的Consumer,而T是Dog,那么也可以接受这个Consumer。

步骤1.首先Objects.requireNonNull,确保传入的action不是null,避免空指针异常,注意是action判空
步骤2.接下来是一个增强的for循环,遍历this,也就是当前的Iterable实例
步骤3.每次循环取出元素t,调用action的accept方法处理它,具体如何处理 t,完全由 Consumer 的实现逻辑决定,是具体的消费操作action

forEach结合Consumer常见场景

(1) 示例 1:打印元素

List<String> list = Arrays.asList("A", "B", "C");
list.forEach(element -> System.out.println(element));

forEach方法参数是 str -> System.out.println(str) :是一个 Consumer< String> 的实现,action就是打印元素:每次调用 accept(t) 时,会执行 System.out.println(t),即打印当前元素。

(2) 示例 2:修改对象状态

List<Person> persons = getPersons();
persons.forEach(person -> person.setAge(18)); // 将所有 Person 的年龄设为 18

逻辑分解:
person -> person.setAge(18) 是 Consumer 的实现。每次调用 accept(t) 时,执行 t.setAge(18),修改元素的状态。

(3) 示例 3:条件判断与过滤

List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
numbers.forEach(num -> {
    if (num % 2 == 0) {
        System.out.println(num + " 是偶数");
    }
});

在 accept(t) 中,根据 t 的值执行条件判断,仅处理满足条件的元素。

(4) 示例 4:方法引用

list.forEach(System.out::println); // 方法引用

等价于:

list.forEach(str -> System.out.println(str));

原理:System.out::println 是 Consumer< String> 的实现,accept(t) 会调用 System.out.println(t)

forEach使用注意细节

①上述的判空处理是判断集合是否或操作是否为空,不是判断集合中的某个元素为null
②对于Null的元素,foreach遍历输出要看具体的子类处理,如List的遍历是将其作为 null字符打印处理

        List<String> list = Arrays.asList("A",null, "C");
        list.forEach(element -> System.out.println(element));

输出

A
null //字符null 不是空 Null
C

(3)Spliterator spliterator()

Spliterator可拆分迭代器介绍链接
流Stream AP介绍点击链接
Spliterator 是 Stream API 并行处理的底层实现,现在的实际工作场景中,应用流对集合进行处理是 非常常见的,代码使用是非常简洁的,这两个单独拿出来说

Iterator< T>迭代器接口

Iterator 是 Java 集合框架中用于遍历集合元素的接口,定义如下:

public interface Iterator<T> {
    boolean hasNext();    // 检查是否还有下一个元素
    T next();             // 返回下一个元素
    void remove();        // 移除当前元素(可选操作)
}

如何“接收” Iterator

(1) 通过集合的 iterator() 方法
有实现了 Iterable 接口的集合类(如 List, Set, Queue)都可通过 iterator() 方法返回迭代器:

List<String> list = Arrays.asList("A", "B", "C");
Iterator<String> iterator = list.iterator(); // 获取迭代器

(2) 自定义集合类实现 Iterable<T>
若需让自定义集合支持迭代,需实现 Iterable 并返回自定义的 Iterator

public class MyCollection<T> implements Iterable<T> {
    private List<T> elements = new ArrayList<>();

    public void add(T element) {
        elements.add(element);
    }

    @Override
    public Iterator<T> iterator() {
        return new MyIterator(); // 返回自定义迭代器
    }

    // 自定义迭代器实现
    private class MyIterator implements Iterator<T> {
        private int index = 0;

        @Override
        public boolean hasNext() {
            return index < elements.size();
        }

        @Override
        public T next() {
            if (!hasNext()) throw new NoSuchElementException();
            return elements.get(index++);
        }

        @Override
        public void remove() {
            elements.remove(--index);
        }
    }
}

核心方法

(1) boolean hasNext()
作用:判断集合中是否还有未被遍历的元素。
返回值:
true:存在下一个元素。
false:已遍历完所有元素。

List<String> list = Arrays.asList("A", "B", "C");
Iterator<String> it = list.iterator();
while (it.hasNext()) { // 检查是否还有元素
    String element = it.next();
    System.out.println(element);
}

(2) T next()
作用:返回当前指向的元素,并将迭代器位置后移。
注意事项:
调用前必须检查 hasNext(),否则可能抛出 NoSuchElementException
返回类型为泛型 T,确保类型安全

Iterator<Integer> it = List.of(1, 2, 3).iterator();
if (it.hasNext()) {
    int num = it.next(); // 返回 1,迭代器指向下一个元素
}

(3) void remove()
作用:移除迭代器最后一次通过 next() 返回的元素。
注意事项:
必须在 next() 之后调用,否则抛出 IllegalStateException
不是所有迭代器都支持此操作,如ArrayList的迭代器执行此操作,不支持删除操作的迭代器如Collections.unmodifiableList()返回的迭代器,调用前需检查是否实现(默认可能抛出 UnsupportedOperationException)。

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String element = it.next();
    if (element.equals("B")) {
        it.remove(); // 移除 "B"
    }
}
System.out.println(list); // 输出 [A, C]

(4) forEachRemaining(Consumer<? super E> action)
上面三个方法是迭代器的核心方法,这个方法是将上面三个方法集合在一起了,他是对父接口的for-each方法的一种补充

    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }

和for-each区别就在于,for-each会将集合中的全部元素按照执行操作执行一遍,forEachRemaining则是将剩余未处理的元素按照执行操作执行一遍,配合可拆分迭代器spliterator中使用样例

List<String> list = Arrays.asList("Java", "Python", "C++", "Go");
Spliterator<String> spliterator = list.spliterator();

// 处理前两个元素
spliterator.tryAdvance(System.out::println); // Java
spliterator.tryAdvance(System.out::println); // Python

// 这时候还剩余两个元素 批量处理剩余元素 
spliterator.forEachRemaining(System.out::println); 

// 输出:
// C++
// Go

迭代器的使用场景

(1) 遍历集合并修改元素

List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3));
Iterator<Integer> it = numbers.iterator();
while (it.hasNext()) {
    int num = it.next();
    if (num % 2 == 0) {
        it.remove(); // 安全删除偶数
    }
}

(2) 遍历不可索引的集合(如 Set)

Set<String> names = new HashSet<>(Set.of("Alice", "Bob"));
Iterator<String> it = names.iterator();
while (it.hasNext()) {
    System.out.println(it.next());
}

(3) 结合流式处理(Stream API)
这种方式也是实际工作中常见的

List<String> list = List.of("Java", "Python", "C++");
list.stream()
    .filter(s -> s.startsWith("J"))
    .forEach(System.out::println); // 输出 "Java"

注意事项

①迭代器的三个方法执行有先后顺序
boolean hasNext(); // 检查是否还有下一个元素
T next(); // 返回下一个元素
void remove(); // 移除当前元素(可选操作)
hasNext() 先保证还有下一个元素 ===》next()指针才做指向下一个元素返回---》指向返回元素才能进行操作元素 remove();删除

②单次遍历:一个迭代器只能遍历集合一次,遍历结束后需重新获取迭代器。不可重复使用迭代器 即每次调用 iterator() 应返回一个新的迭代器实例。

③并发修改

List<String> list = new ArrayList<>(Arrays.asList("A", "B"));
Iterator<String> it = list.iterator();
list.add("C"); // 直接修改集合
it.next();     // 抛出 ConcurrentModificationException

解决方案:使用并发集合(如 CopyOnWriteArrayList)或在迭代期间仅通过迭代器修改集合

总结

1.迭代Iterable接口和迭代器Iterator接口 联系与区别
①关联:Iterable接口主要生成迭代器和增强for each循环,而增强的 for-each 循环底层依赖 Iterator,无论是在集合还是数组上使用 for-each 循环,其内部都会转换为相应的迭代器操作,具体的实现方式需要去查看迭代接口的实现类,如ArrayList

//增强for each循环
for (String s : list) {
    System.out.println(s);
}
//等价于:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String s = it.next();
    System.out.println(s);
}

②区别:除此之外迭代器提供了一种更为安全的删除元素的操作方式,即迭代器的三个关键方法:hasNext(), next(), remove()配合使用,当仅仅需要遍历集合使用for-each就可以,但如果需要删除元素时,可以使用迭代器的 remove() 方法,两者的主要区别

Iterable<T>Iterator<T>
表示对象可被迭代实际执行迭代操作
定义 iterator() 方法定义 hasNext(), next(), remove()
支持 for-each 循环手动控制遍历过程

2.集合框架中几乎所有集合类都实现了 Iterable,例如

  • List(如 ArrayList, LinkedList)
  • Set(如 HashSet, TreeSet)
  • Queue(如 PriorityQueue)

表名这些集合类都是可以被迭代的,当然也都都可以使用迭代器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2331303.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MATLAB2024a超详细图文安装教程(2025最新版保姆级教程)附安装钥

目录 前言 一、MATLAB下载 二、MATLAB安装 二、MATLAB启动 前言 MATLAB&#xff08;Matrix Laboratory&#xff09;是由MathWorks公司开发的一款高性能的编程语言和交互式环境&#xff0c;主要用于数值计算、数据分析和算法开发。内置数学函数和工具箱丰富&#xff0c;开发…

基于 Spring Boot 瑞吉外卖系统开发(二)

基于 Spring Boot 瑞吉外卖系统开发&#xff08;二&#xff09; 员工登录功能实现 员工登录页面login.html存放在/resources/backend/page/login目录下。 启动项目&#xff0c;在浏览器中通过地址“http://localhost:8080/backend/page/login/login.html”访问员工登录页面。…

软考系统架构设计师之大数据与人工智能笔记

一、大数据架构设计 1. 核心概念与挑战 大数据特征&#xff1a;体量大&#xff08;Volume&#xff09;、多样性&#xff08;Variety&#xff09;、高速性&#xff08;Velocity&#xff09;、价值密度低&#xff08;Value&#xff09;。传统数据库问题&#xff1a;数据过载、性…

146. LRU 缓存 带TTL的LRU缓存实现(拓展)

LRU缓存 方法一:手动实现双向链表 哈希表 struct Node{int val;int key;Node* prev;Node* next;Node(int a, int b): key(a), val(b), prev(nullptr), next(nullptr) {}Node():key(0), val(0), prev(nullptr), next(nullptr) {} }; class LRUCache { private:Node* removeTai…

浅层神经网络:全面解析(扩展)

浅层神经网络&#xff1a;全面解析&#xff08;扩展&#xff09; 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;可以分享一下给大家。点击跳转到网站。 https://www.captainbed.cn/ccc 一、神经网络架构演进图谱 #mermaid-svg-…

Qt 事件系统负载测试:深入理解 Qt 事件处理机制

Qt 事件系统负载测试&#xff1a;深入理解 Qt 事件处理机制 文章目录 Qt 事件系统负载测试&#xff1a;深入理解 Qt 事件处理机制摘要引言实现原理1. 自定义事件类型2. 事件队列管理3. 性能指标监控4. 事件发送机制 性能监控实现1. 负载计算2. 内存监控3. 延迟计算 使用效果优化…

Unity3D仿星露谷物语开发33之光标位置可视化

1、目标 当从道具栏中拖出一个道具到地面的时候&#xff0c;光标区域会显示是否可放置物体的可视化显示。绿色表示可以放置物体&#xff0c;红色表示不可以放置物体。 2、优化InventoryManager脚本 添加2个方法&#xff1a; /// <summary>/// Returns the itemDetails&…

蓝桥杯冲刺题单--二分

二分 知识点 二分&#xff1a; 1.序列二分&#xff1a;在序列中查找&#xff08;不怎么考&#xff0c;会比较难&#xff1f;&#xff09; 序列二分应用的序列必须是递增或递减&#xff0c;但可以非严格 只要r是mid-1&#xff0c;就对应mid&#xff08;lr1&#xff09;/2 2.答…

MySQL原理(一)

目录 一、理解MySQL的服务器与客户端关系 1&#xff1a;MySQL服务器与客户端 2&#xff1a;服务器处理客户端请求 3&#xff1a;常见的存储引擎 二、字符集和比较规则 1&#xff1a;字符集和比较规则简介 2&#xff1a;字符集和比较规则应用 3&#xff1a;乱码原因&…

Docker+Jenkins+Gitee自动化项目部署

前置条件 docker安装成功 按照下面配置加速 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF {"registry-mirrors": ["https://register.librax.org"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker一、…

VScode 画时序图(FPGA)

1、先安装插件&#xff1a; 2、然后就可以编写一个.js文件&#xff0c;如下&#xff1a; {signal: [{name: clk, wave: p.......|..},{name: rstn, wave: 01......|..},{name: din_vld, wave: 0.1.0...|..},{name: din, wave: "x.x...|..", data: ["D0", …

一文详解OpenCV环境搭建:Windows使用CLion配置OpenCV开发环境

在计算机视觉和图像处理领域&#xff0c;OpenCV 是一个不可或缺的工具。其为开发者提供了一系列广泛的算法和实用工具&#xff0c;支持多种编程语言&#xff0c;并且可以在多个平台上运行。对于希望在其项目中集成先进视觉功能的开发者来说&#xff0c;掌握如何配置和使用OpenC…

计算机网络 3-2 数据链路层(流量控制与可靠传输机制)

3.4 流量控制与可靠传输机制 流量控制&#xff1a;指由接收方控制发送方的发送速率&#xff0c;使接收方有足够的缓冲空间来接收每个帧 滑动窗口流量控制:一种更高效的流量控制方法。 在任意时刻&#xff0c;发送方都维持一组连续的允许发送帧的序号&#xff0c;称为发送窗口…

Jenkins配置的JDK,Maven和Git

1. 前置 在配置前&#xff0c;我们需要先把JDK&#xff0c;Maven和Git安装到Jenkins的服务器上。 &#xff08;1&#xff09;需要进入容器内部&#xff0c;执行命令&#xff1a;docker exec -u root -it 容器号/容器名称&#xff08;2选1&#xff09; bash -- 容器名称 dock…

有效压缩 Hyper-v linux Centos 的虚拟磁盘 VHDX

参考&#xff1a; http://www.360doc.com/content/22/0505/16/67252277_1029878535.shtml VHDX 有个不好的问题就是&#xff0c;如果在里面存放过文件再删除&#xff0c;那么已经使用过的空间不会压缩&#xff0c;导致空间一直被占用。那么就需要想办法压缩空间。 还有一点&a…

网络空间安全(53)XSS

一、定义与原理 XSS&#xff08;Cross Site Scripting&#xff09;&#xff0c;全称为跨站脚本攻击&#xff0c;是一种网站应用中的安全漏洞攻击。其原理是攻击者利用网站对用户输入内容校验不严格等漏洞&#xff0c;将恶意脚本&#xff08;通常是JavaScript&#xff0c;也可以…

Spring MVC 框架 的核心概念、组件关系及流程的详细说明,并附表格总结

以下是 Spring MVC 框架 的核心概念、组件关系及流程的详细说明&#xff0c;并附表格总结&#xff1a; 1. 核心理念 Spring MVC 是基于 MVC&#xff08;Model-View-Controller&#xff09;设计模式 的 Web 框架&#xff0c;其核心思想是 解耦&#xff1a; Model&#xff1a;数…

金融数据分析(Python)个人学习笔记(6):安装相关软件

python环境的安装请查看Python个人学习笔记&#xff08;1&#xff09;&#xff1a;Python软件的介绍与安装 一、pip 在windows系统中检查是否安装了pip 打开命令提示符的快捷键&#xff1a;winR&#xff0c;然后输入cmd 在命令提示符中执行如下命令 python -m pip --version…

一周学会Pandas2 Python数据处理与分析-Pandas2一维数据结构-Series

锋哥原创的Pandas2 Python数据处理与分析 视频教程&#xff1a; 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili Pandas提供Series和DataFrame作为数组数据的存储框架。 Series&#xff08;系列、数列、序列&#xff09;是一个带有…

DApp实战篇:前端技术栈一览

前言 在前面一系列内容中&#xff0c;我们由浅入深地了解了DApp的组成&#xff0c;从本小节开始我将带领大家如何完成一个完整的DApp。 本小节则先从前端开始。 前端技术栈 在前端开发者速入&#xff1a;DApp中的前端要干些什么&#xff1f;文中我说过&#xff0c;即便是在…