什么是迭代器?
迭代器(Iterator)是一种设计模式,它提供了一种统一的方法来顺序访问集合中的元素,而不需要了解集合的内部结构。Java中的迭代器接口让我们可以遍历任何Collection类型的集合。
生活比喻
迭代器就像博物馆的语音导览器。无论你参观的是绘画馆、雕塑馆还是文物馆,导览器都提供相同的操作:当前展品是什么?(hasNext())下一件展品是什么?(next())讲解完毕(remove())。游客不需要知道博物馆是如何布置展厅的。
迭代器遍历集合的流程:
┌─────────────────────────────────────────────┐
│ │
│ hasNext() ──→ true ──→ next() ──→ 处理元素 │
│ ↑ ↓ │
│ └──── false (遍历结束) ←──┘ │
│ │
│ remove() 可在 next() 之后调用删除元素 │
└─────────────────────────────────────────────┘
Iterator接口的方法
Iterator接口只有三个核心方法,简单却功能强大:
| 方法 | 返回类型 | 说明 |
|---|---|---|
| hasNext() | boolean | 判断是否还有下一个元素 |
| next() | E | 返回下一个元素,并将迭代器位置前移 |
| remove() | void | 删除上次调用next()返回的元素 |
Iterator基本用法
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorBasicDemo {
public static void main(String[] args) {
List fruits = new ArrayList<>();
fruits.add("苹果");
fruits.add("香蕉");
fruits.add("橙子");
fruits.add("芒果");
// 获取迭代器
Iterator iterator = fruits.iterator();
// 遍历
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println("水果: " + fruit);
}
System.out.println("遍历完成!");
}
}
为什么要用迭代器?
优势1:统一遍历方式
无论是List、Set还是Queue,都可以使用Iterator进行遍历。这种统一性让你可以在不知道集合具体类型的情况下遍历它。
// 这个方法可以遍历任何Collection集合
public void printAll(Collection> collection) {
Iterator> it = collection.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
// 使用
printAll(new ArrayList<>());
printAll(new HashSet<>());
printAll(new LinkedList<>());
优势2:安全删除元素
在遍历集合时,如果你直接使用for循环或foreach循环删除元素,可能会抛出ConcurrentModificationException异常。迭代器的remove()方法是专门设计来在遍历过程中安全删除元素的。
错误做法 vs 正确做法:
❌ 错误:foreach中删除
for (String s : list) {
if (s.equals("要删除的")) {
list.remove(s); // ConcurrentModificationException!
}
}
✓ 正确:使用迭代器删除
Iterator it = list.iterator();
while (it.hasNext()) {
if (it.next().equals("要删除的")) {
it.remove(); // 安全删除
}
}
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class SafeRemoveDemo {
public static void main(String[] args) {
List numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
numbers.add(5);
numbers.add(6);
System.out.println("删除前: " + numbers);
// 使用迭代器安全删除所有偶数
Iterator it = numbers.iterator();
while (it.hasNext()) {
Integer num = it.next();
if (num % 2 == 0) {
it.remove(); // 安全删除
System.out.println("删除了: " + num);
}
}
System.out.println("删除后: " + numbers); // [1, 3, 5]
}
}
ListIterator双向迭代器
ListIterator是List接口特有的迭代器,继承自Iterator。它支持双向遍历,还可以在遍历过程中修改列表。
| 方法 | 说明 |
|---|---|
| hasNext() | 判断是否有下一个元素(正向) |
| next() | 返回下一个元素(正向) |
| hasPrevious() | 判断是否有上一个元素(反向) |
| previous() | 返回上一个元素(反向) |
| nextIndex() | 返回下一个元素的索引 |
| previousIndex() | 返回上一个元素的索引 |
| add(E e) | 在当前位置添加元素 |
| set(E e) | 替换上次返回的元素 |
| remove() | 删除上次返回的元素 |
import java.util.ArrayList;
import java.util.ListIterator;
public class ListIteratorDemo {
public static void main(String[] args) {
ArrayList cities = new ArrayList<>();
cities.add("北京");
cities.add("上海");
cities.add("广州");
cities.add("深圳");
ListIterator it = cities.listIterator();
System.out.println("===== 正向遍历 =====");
while (it.hasNext()) {
int index = it.nextIndex();
String city = it.next();
System.out.println(index + ": " + city);
}
System.out.println("\n===== 反向遍历 =====");
while (it.hasPrevious()) {
int index = it.previousIndex();
String city = it.previous();
System.out.println(index + ": " + city);
}
System.out.println("\n===== 添加和修改 =====");
// 把迭代器移回开始位置
while (it.hasNext()) {
it.next();
}
// 现在可以反向操作
while (it.hasPrevious()) {
String city = it.previous();
if (city.equals("上海")) {
it.set("上海市"); // 修改
it.add("杭州"); // 添加
}
}
System.out.println("修改后: " + cities);
}
}
Iterator的高级用法
1. 遍历Map
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class MapIteratorDemo {
public static void main(String[] args) {
Map scores = new HashMap<>();
scores.put("张三", 95);
scores.put("李四", 87);
scores.put("王五", 92);
// 方法1:遍历entrySet
System.out.println("方法1: 遍历entrySet");
Iterator> entryIt = scores.entrySet().iterator();
while (entryIt.hasNext()) {
Map.Entry entry = entryIt.next();
System.out.println(entry.getKey() + " = " + entry.getValue());
}
// 方法2:遍历keySet
System.out.println("\n方法2: 遍历keySet");
Iterator keyIt = scores.keySet().iterator();
while (keyIt.hasNext()) {
String key = keyIt.next();
System.out.println(key + " = " + scores.get(key));
}
// 方法3:使用Lambda(Java 8+)
System.out.println("\n方法3: forEach + Lambda");
scores.forEach((k, v) -> System.out.println(k + " = " + v));
}
}
2. 条件删除多个元素
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class BatchRemoveDemo {
public static void main(String[] args) {
List words = new ArrayList<>();
words.add("apple");
words.add("banana");
words.add("apricot");
words.add("blueberry");
words.add("cherry");
// 删除所有以"a"开头的单词
Iterator it = words.iterator();
while (it.hasNext()) {
if (it.next().startsWith("a")) {
it.remove();
}
}
System.out.println("删除后: " + words);
}
}
3. 并行迭代(小心使用)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorCaution {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
// 注意:一个迭代器不能用于两个独立的遍历
Iterator it = list.iterator();
it.next(); // 读取第一个
// 如果再创建一个新的迭代器进行遍历
Iterator it2 = list.iterator(); // 新迭代器从头开始
// 两个迭代器独立使用是可以的
System.out.println("迭代器1: " + it.next()); // B
System.out.println("迭代器2: " + it2.next()); // A
}
}
常见错误和注意事项
错误1:在调用next()之前先调用remove()
迭代器的remove()方法删除的是上次next()返回的元素。如果在还没调用next()之前就调用remove(),会抛出IllegalStateException。
Iterator it = list.iterator();
it.remove(); // ❌ IllegalStateException! 还没调用next()
错误2:连续调用两次remove()
每次remove()之后,上次返回的元素已经被删除了。如果不再次调用next()就调用remove(),会抛出IllegalStateException。
it.next();
it.remove();
it.remove(); // ❌ IllegalStateException! 需要先再调用next()
错误3:在迭代过程中修改集合(除迭代器的remove外)
在迭代集合时,如果通过其他方式(如list.remove())修改集合,会导致ConcurrentModificationException。
提示:Java 8+的forEach
对于简单的遍历,Java 8引入的forEach方法和Stream API提供了更简洁的写法。但迭代器仍然是修改集合的首选方式。
迭代器vs增强for循环
| 特性 | Iterator | 增强for循环 |
|---|---|---|
| 代码简洁性 | 较繁琐 | 简洁 |
| 安全删除 | 支持 | 不支持(会抛异常) |
| 双向遍历 | ListIterator支持 | 不支持 |
| 知道当前位置 | 可以 | 不知道 |
| 适用场景 | 需要删除元素时 | 仅遍历时 |
小结
- Iterator提供了一种统一、安全的方式遍历任何Collection集合
- 三个核心方法:hasNext()、next()、remove()
- 使用迭代器的remove()可以在遍历时安全删除元素
- ListIterator支持双向遍历和修改元素
- 不要在迭代过程中通过其他方式修改集合
- 增强for循环适合仅需要遍历的场景,需要删除时用迭代器