一、什么是迭代器?
迭代器是 Java 集合框架中的一种设计模式 ,它的核心作用是:提供一种统一的方式遍历集合中的元素,而不需要暴露集合内部的实现细节。
你可以把它想象成一个"游标":
- 一开始指向集合的第一个元素之前
- 通过调用方法可以逐个移动游标并获取元素
- 遍历完成后游标指向集合末尾
二、入门级讲解:基本用法
1. 核心接口定义
Java 中所有迭代器都实现了 java.util.Iterator 接口,核心方法只有三个:
java
public interface Iterator<E> {
// 判断是否还有下一个元素
boolean hasNext();
// 获取下一个元素(调用前必须先判断hasNext())
E next();
// 删除当前迭代到的元素(可选操作)
default void remove() {
throw new UnsupportedOperationException("remove");
}
}
2. 最简单的遍历示例
以最常用的 ArrayList 为例,演示基础遍历流程:
java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorBasicDemo {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("苹果");
fruits.add("香蕉");
fruits.add("橙子");
// 1. 获取迭代器
Iterator<String> iterator = fruits.iterator();
// 2. 遍历集合
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println("当前水果:" + fruit);
// 可选:删除符合条件的元素(注意不能用集合的remove方法)
if ("香蕉".equals(fruit)) {
iterator.remove();
}
}
System.out.println("删除香蕉后的集合:" + fruits);
}
}
运行结果:
当前水果:苹果
当前水果:香蕉
当前水果:橙子
删除香蕉后的集合:[苹果, 橙子]
三、实战进阶:实用场景与避坑指南
1. 遍历中安全删除元素
⚠️ 关键注意点 :在迭代过程中,不能直接调用集合的 remove() 方法,否则会抛出 ConcurrentModificationException 并发修改异常。必须使用迭代器自身的 remove() 方法。
错误示例:
java
// 错误写法:遍历中直接修改集合
for (String fruit : fruits) {
if ("香蕉".equals(fruit)) {
fruits.remove(fruit); // 会抛出异常
}
}
2. 增强 for 循环与迭代器的关系
Java 的增强 for 循环(for-each)本质上是迭代器的语法糖,编译后会自动转换成迭代器遍历:
java
// 等价于上面的迭代器写法
for (String fruit : fruits) {
System.out.println(fruit);
}
3. 反向迭代器:ListIterator
对于有序集合(如 ArrayList),可以使用 ListIterator 实现双向遍历:
java
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListIteratorDemo {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
// 获取从末尾开始的迭代器
ListIterator<Integer> iterator = numbers.listIterator(numbers.size());
// 反向遍历
while (iterator.hasPrevious()) {
Integer num = iterator.previous();
System.out.println("反向遍历:" + num);
}
}
}
运行结果:
反向遍历:3
反向遍历:2
反向遍历:1
4. 迭代器的应用场景
- 遍历各种集合(List、Set、Map 的 entrySet/keySet 等)
- 在遍历中安全删除元素
- 统一不同集合的遍历方式(不管是 ArrayList 还是 HashSet,都用同样的迭代器接口)
四、优缺点与特点总结
| 特性 | 详细说明 |
|---|---|
| ✅ 优点 | 1. 统一遍历接口,无需关心集合内部实现 2. 遍历中安全删除元素 3. 支持单向/双向遍历(ListIterator) 4. 解耦集合与遍历逻辑 |
| ❌ 缺点 | 1. 只能单向遍历(普通 Iterator),不能随机访问 2. 遍历过程中不能修改集合(除了迭代器自身的 remove 方法 ) 3. 比普通 for 循环(基于索引)的性能略低(对 ArrayList 这类随机访问集合) |
| 🎯 核心特点 | 1. 迭代器是一次性的 :遍历完成后需要重新获取才能再次遍历 2. 快速失败(Fail-Fast)机制:如果在迭代过程中集合被修改,会立即抛出异常 |
五、类似遍历方式对比
| 遍历方式 | 适用场景 | 性能 | 可修改性 |
|---|---|---|---|
| 迭代器 Iterator | 所有集合类型,需要在遍历中删除元素 | 中等(LinkedList 比索引遍历快) | 仅支持迭代器的 remove() |
| 增强 for 循环 | 仅需要读取元素,不需要修改 | 与迭代器一致 | 不能修改集合 |
| 普通 for 循环(索引) | 仅支持有序集合(List),需要随机访问 | 对 ArrayList 最快 | 可以直接修改集合,但遍历中删除会导致元素索引混乱 |
| forEach() 方法(Java 8+) | 函数式编程风格,仅读取元素 | 与迭代器一致 | 不能修改集合(会抛出异常) |
对比示例:
java
// 1. 普通索引遍历(仅适用于List)
for (int i = 0; i < fruits.size(); i++) {
System.out.println(fruits.get(i));
}
// 2. Java 8+ forEach 方法
fruits.forEach(fruit -> System.out.println(fruit));