杰瑞科技汇

Java Iterator接口的核心作用与使用场景?

Iterator 是 Java 集合框架中一个非常核心和基础的接口,它提供了一种统一的方式来遍历集合(Collection)中的元素,而无需关心集合底层的具体实现。

Java Iterator接口的核心作用与使用场景?-图1
(图片来源网络,侵删)

什么是 Iterator

Iterator 的设计遵循了迭代器模式,它的核心思想是将遍历操作与集合本身分离

想象一下,你去图书馆看书,如果你直接走进书库,自己一本本地找,这就像直接使用集合的 get(index) 方法(ArrayList),效率低下且逻辑混乱。

而更好的方式是,你向图书管理员(Iterator)借一个“书单”,然后按照书单的顺序一本一本地取书,你不需要关心书是按什么规则排列的(按作者、按分类还是按入库时间),你只需要按照书单(Iterator)的指示来操作即可。

Iterator 就扮演了这个“书单”的角色,它告诉你:

Java Iterator接口的核心作用与使用场景?-图2
(图片来源网络,侵删)
  1. 是否还有下一本书? (hasNext())
  2. 请给我下一本书。 (next())
  3. 我不想要这本书了,请把它放回原处。 (remove())

Iterator 接口的核心方法

java.util.Iterator 接口定义了三个核心方法:

方法 描述 返回值
boolean hasNext() 检查迭代中是否还有更多的元素,如果有,返回 true;否则返回 false boolean
E next() 返回迭代中的下一个元素。 元素类型 E
default void remove() 可选操作,从迭代器最后一次返回的元素集合中移除该元素,每次调用 next() 后只能调用一次 remove() void

重要提示:

  • remove() 是一个 default 方法(Java 8 引入),意味着 Iterator 接口提供了默认实现,但集合的具体实现类可以选择覆盖它,很多情况下,调用 remove() 方法会抛出 UnsupportedOperationException
  • remove() 方法是安全地在遍历过程中修改集合的方式,它会同步更新迭代器和集合的状态,避免 ConcurrentModificationException(并发修改异常)。

如何获取和使用 Iterator

几乎所有实现了 Collection 接口的类都提供了一个 iterator() 方法,用于返回一个该集合的 Iterator 对象。

基本使用示例

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorExample {
    public static void main(String[] args) {
        // 1. 创建一个 List 集合
        List<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        fruits.add("Mango");
        System.out.println("原始集合: " + fruits);
        // 2. 通过 iterator() 方法获取迭代器
        Iterator<String> iterator = fruits.iterator();
        // 3. 使用迭代器遍历集合
        System.out.println("\n使用迭代器遍历集合:");
        while (iterator.hasNext()) {
            // 4. 获取下一个元素
            String fruit = iterator.next();
            System.out.println("当前水果: " + fruit);
            // 5. 示例:移除 "Orange"
            if ("Orange".equals(fruit)) {
                System.out.println("发现 Orange,准备移除...");
                iterator.remove(); // 安全地移除元素
            }
        }
        System.out.println("\n移除 Orange 后的集合: " + fruits);
    }
}

输出结果:

Java Iterator接口的核心作用与使用场景?-图3
(图片来源网络,侵删)
原始集合: [Apple, Banana, Orange, Mango]
使用迭代器遍历集合:
当前水果: Apple
当前水果: Banana
当前水果: Orange
发现 Orange,准备移除...
当前水果: Mango
移除 Orange 后的集合: [Apple, Banana, Mango]

代码解析:

  1. 我们创建了一个 ArrayList 并添加了一些元素。
  2. 调用 fruits.iterator() 获取了 Iterator 实例。
  3. 使用 while (iterator.hasNext()) 循环,这是标准的迭代器遍历模式,确保在尝试获取元素之前先检查是否存在。
  4. iterator.next() 获取元素并移动指针。
  5. 当元素是 "Orange" 时,我们调用 iterator.remove(),这个方法会从底层的 ArrayList 中移除 "Orange",并且不会破坏迭代器的状态。

for-each 循环与 Iterator 的关系

你可能更熟悉 for-each 循环(增强 for 循环),它在代码上更简洁。

for (String fruit : fruits) {
    System.out.println(fruit);
}

for-eachIterator 是什么关系呢?

答案是:for-each 循环的内部实现就是 Iterator

当你编译上面的 for-each 代码时,JVM 会将其转换成类似下面这样的基于 Iterator 的代码:

Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
    String fruit = iterator.next();
    System.out.println(fruit);
}

这意味着:

  • 所有可以使用 for-each 循环的类,都必须实现了 Iterable 接口。
  • Iterable 接口中定义了一个 iterator() 方法,这正是 for-each 循环所需要的。

Iterable 接口定义:

public interface Iterable<T> {
    Iterator<T> iterator(); // 返回一个迭代器
    // ... 其他默认方法
}

for-each 循环会自动调用这个 iterator() 方法来获取迭代器,然后使用 hasNext()next() 进行遍历。


Iterator vs. ListIterator

Iterator 有一个更强大的子接口——ListIterator,它专门用于遍历 List 集合。

特性 Iterator ListIterator
适用范围 所有 Collection List
遍历方向 单向(只能向后) 双向(可以向前向后)
额外方法 hasNext(), next(), remove() hasNext(), next()<br>hasPrevious(), previous()<br>add(E e), set(E e)<br>nextIndex(), previousIndex()

ListIterator 的优势:

  • 双向遍历:可以使用 hasPrevious()previous() 从后向前遍历。
  • 添加元素add(E e) 方法可以在当前位置插入一个新元素。
  • 修改元素set(E e) 方法可以替换最后一次返回的元素。

Iterator 的注意事项

  1. ConcurrentModificationException (并发修改异常)

    • 场景:当你使用 Iterator 遍历一个集合时,如果不是通过 iterator.remove() 方法,而是通过集合自身的 remove() 方法(或其他修改集合结构的方法)来修改集合,就会抛出此异常。
    • 原因:迭代器创建后,会维护一个“预期修改次数”(expectedModCount),每次集合被结构性修改(增、删)时,modCount 会自增,当迭代器执行 next()remove() 时,它会检查 expectedModCount 是否等于 modCount,如果不等,说明在迭代过程中集合被其他方式修改了,迭代器认为其状态已失效,于是抛出异常。
    • 解决方案:如果需要在遍历时删除元素,务必使用 iterator.remove()
  2. NoSuchElementException

    • 场景:当 iterator.hasNext() 返回 false 时,如果再调用 iterator.next(),就会抛出此异常。
    • 原因:表示已经到达集合的末尾,没有更多元素可以获取了。
  3. IllegalStateException

    • 场景:在不允许的情况下调用 remove() 方法。
    • 原因:通常发生在以下情况:
      • 在调用 next() 之前就调用了 remove()
      • 在一次 next() 调用后,连续调用了两次 remove()

特性 描述
核心作用 提供一种统一、安全的方式来遍历集合元素。
设计模式 迭代器模式,将遍历逻辑与集合实现解耦。
关键方法 hasNext(), next(), remove()
获取方式 通过集合的 iterator() 方法获得。
for-each 关系 for-each 循环是 Iterator 的语法糖,底层实现依赖 Iterable 接口。
安全删除 在遍历过程中删除元素,必须使用 iterator.remove()
局限性 Iterator 是单向的,对于 List,如果需要更强大的功能(如双向遍历、增删改),应使用 ListIterator

掌握 Iterator 是理解 Java 集合框架的关键一步,它不仅是一种遍历工具,更体现了 Java 设计中“解耦”和“统一接口”的优秀思想。

分享:
扫描分享到社交APP
上一篇
下一篇