1. 什么是 Iterator?
Iterator 是 Java 集合框架中用于遍历集合元素的接口,位于 java.util 包下。
它提供了一种统一的方式来遍历 Collection(如 List、Set)中的元素,而无需关心底层实现。
2. Iterator 的常用方法
| 方法 | 说明 |
|---|---|
boolean hasNext() | 是否还有下一个元素 |
E next() | 返回下一个元素,并将游标向后移动 |
void remove() | 移除当前迭代器返回的元素(可选操作) |
default void forEachRemaining(Consumer) | 对剩余元素执行指定操作(Java 8+) |
3. 使用示例
3.1 遍历 List
List<String> list = Arrays.asList("A", "B", "C");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
}
3.2 遍历 Set
Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3));
Iterator<Integer> it = set.iterator();
while (it.hasNext()) {
Integer num = it.next();
System.out.println(num);
}
3.3 使用 remove() 删除元素
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (item.equals("b")) {
iterator.remove(); // 删除当前元素
}
}
System.out.println(list); // 输出: [a, c]
注意:
不能在遍历时直接用 list.remove(item),否则会抛 ConcurrentModificationException。
4. Iterator 的底层原理
- 每个集合类(如 ArrayList、HashSet)都有自己的内部迭代器实现。
- 迭代器内部维护一个游标(指针),每次调用
next()时,游标向后移动。 hasNext()判断游标是否到达末尾。
5. Iterator 的常见异常
5.1 NoSuchElementException
当没有元素可遍历时,继续调用 next() 会抛出此异常。
示例:
List<String> list = new ArrayList<>();
Iterator<String> it = list.iterator();
it.next(); // 抛 NoSuchElementException
5.2 ConcurrentModificationException
在使用迭代器遍历集合的过程中,如果直接用集合的方法(如 remove()、add())修改集合,会抛出此异常。
示例:
List<String> list = new ArrayList<>(Arrays.asList("a", "b"));
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
list.remove(s); // 抛 ConcurrentModificationException
}
正确做法: 用 iterator.remove()。
6. for-each 与 Iterator 的关系
Java 的 for-each(增强型 for 循环)底层其实也是用 Iterator 实现的。例如:
for (String s : list) {
System.out.println(s);
}
等价于:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
7. forEachRemaining 的用法(Java 8+)
Iterator<String> it = list.iterator();
it.forEachRemaining(item -> System.out.println(item));
对剩余的元素执行 lambda 表达式。
8. 适用场景
- 需要在遍历过程中安全地删除元素时。
- 需要对不同类型的集合统一遍历时。
- 需要手动控制遍历流程时。
9. 小结与注意事项
- 遍历时用
hasNext()判断是否有元素,next()取元素。 - 删除元素应使用
iterator.remove()。 - 不要在遍历时直接用集合的添加/删除方法。
- for-each 循环底层也是用 Iterator 实现的。
10. ListIterator 与 Iterator 的区别
ListIterator 是 Iterator 的子接口,只能用于 List(如 ArrayList、LinkedList),功能更强大:
| 特性 | Iterator | ListIterator |
|---|---|---|
| 支持遍历方向 | 只能向前 | 可以双向(前/后)遍历 |
| 支持元素修改 | 只能删除 | 可增、删、改元素 |
| 可获取当前索引 | 无 | 有(nextIndex/previousIndex) |
| 适用集合类型 | 所有 Collection | 仅 List |
示例:
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
ListIterator<String> it = list.listIterator();
while (it.hasNext()) {
String s = it.next();
if (s.equals("b")) {
it.set("B"); // 修改元素
it.add("bb"); // 插入元素
}
}
System.out.println(list); // 输出: [a, B, bb, c]
11. 线程安全问题
1. 普通集合的 Iterator 不是线程安全的
在多线程环境下,若一个线程遍历,另一个线程修改集合,可能会抛 ConcurrentModificationException。
2. 解决办法
- 使用
Collections.synchronizedList()包装集合 - 或使用并发集合(如
CopyOnWriteArrayList)
示例:
List<String> list = Collections.synchronizedList(new ArrayList<>());
synchronized (list) {
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
12. 如何自定义 Iterator
如果你自己写了一个集合类,也可以实现 Iterable 接口,并提供自己的 Iterator:
public class MyCollection implements Iterable<String> {
private String[] data = {"x", "y", "z"};
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
private int index = 0;
public boolean hasNext() {
return index < data.length;
}
public String next() {
if (!hasNext()) throw new NoSuchElementException();
return data[index++];
}
};
}
}
这样你的集合就可以用 for-each 或 Iterator 方式遍历了。
13. 实际开发建议
- 删除元素时用 iterator.remove(),不要直接用集合的 remove。
- 遍历前判断集合是否为空,避免空指针异常。
- 在多线程环境下,优先考虑并发集合或加锁。
- 不要在遍历时修改集合结构(增删元素),除非用 iterator.remove()/listIterator.add()。
- 使用 for-each 循环时不能删除元素,否则会报错。
14. 常见面试题
- Iterator 和 ListIterator 有什么区别?
- 如何安全地遍历并删除集合中的元素?
- 为什么直接用集合的 remove 方法会抛 ConcurrentModificationException?
- Iterator 的底层原理是什么?
- 如何自定义一个集合的 Iterator?
15. 代码示例:安全删除元素
List<Integer> nums = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
Iterator<Integer> it = nums.iterator();
while (it.hasNext()) {
Integer n = it.next();
if (n % 2 == 0) {
it.remove(); // 删除偶数
}
}
System.out.println(nums); // 输出: [1, 3, 5]
16. 其他高级用法
使用 forEachRemaining (Java 8+)
Iterator<String> it = list.iterator();
it.forEachRemaining(s -> {
// 对剩余元素做操作
System.out.println(s);
});
迭代 Map
遍历 Map 时,通常用 entrySet() 获取键值对:
Map<String, Integer> map = new HashMap<>();
map.put("A", 1); map.put("B", 2);
Iterator<Map.Entry<String, Integer>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Integer> entry = it.next();
System.out.println(entry.getKey() + ": " + entry.getValue());
}
17. 总结
- Iterator 是遍历集合的标准工具,支持安全删除。
- ListIterator 适合 List,支持双向遍历和元素修改。
- 多线程环境要用并发集合或加锁。
- 删除元素用 iterator.remove(),不要用集合的 remove。
- for-each 循环底层也是 Iterator。
- 熟悉这些用法,能避免常见异常和编程陷阱。
1341





