前言
上一篇我们讲解了集合整体架构、Collection 顶层接口基础 API,本篇学习所有单列集合通用的三种遍历方式:迭代器、增强 for 循环、forEach 方法,同时拆解迭代器底层源码,搞懂指针移动原理。
一、前置区分:哪些集合能用通用遍历
- List 接口:有索引,除通用三种遍历外,还支持普通 for 循环
- Set 接口:无索引,只能使用本篇三种通用遍历单列集合全部实现 Iterable 接口,所以都支持迭代器遍历。
二、方式 1:迭代器 Iterator 遍历
1. 迭代器核心两个方法
| 方法 | 作用 |
|---|---|
boolean hasNext() |
判断集合是否还有未取出元素,有返回 true,无返回 false |
E next() |
取出当前指针指向的元素,同时指针自动后移一位 |
2. 基础代码示例
import java.util.ArrayList;
import java.util.Iterator;
public class IteratorDemo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("拿");
list.add("了");
list.add("橘");
list.add("子");
list.add("跑");
list.add("啊");
// 1. 获取迭代器对象
Iterator<String> it = list.iterator();
// 2. while循环判断是否有下一个元素
while(it.hasNext()){
// 取出元素,指针后移
String s = it.next();
System.out.println(s);
}
}
}
重要注意点
循环中next()方法只调用一次,多次调用会出现元素跳跃、NoSuchElementException 异常。
3. ArrayList 迭代器底层源码解析
private class Itr implements Iterator<E> {
int cursor; // 指针,记录当前待取元素下标
int lastRet = -1;
// 判断是否还有元素
public boolean hasNext() {
return cursor != size;
}
// 取出元素,指针+1
public E next() {
int i = cursor;
cursor = i + 1;
return (E) elementData[lastRet = i];
}
}
运行逻辑:
- cursor 初始值 0,size 为集合总元素数量;
hasNext()判断 cursor 是否等于 size,不等代表还有元素;next()先保存当前 cursor 下标,cursor 自增 1,再取出数组对应下标元素返回;- 当 cursor 等于 size 时,
hasNext()返回 false,循环结束。
迭代器小结
Iterator<String> it = 集合对象.iterator();
while(it.hasNext()) {
String s = it.next();
System.out.println(s);
}
hasNext():判断剩余元素next():取元素 + 指针后移- 禁止循环内多次调用 next ()
三、方式 2:增强 for 循环(JDK5 推出)
1. 底层本质
内部依旧封装 Iterator 迭代器,简化迭代器代码书写,仅用于遍历集合 / 数组,无法在遍历过程中修改集合。
2. 语法格式
for (元素数据类型 变量名 : 集合/数组) {
// 使用变量
}
3. 代码演示
import java.util.ArrayList;
public class ForEachDemo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
// 增强for遍历
for (String s : list) {
System.out.println(s);
}
}
}
四、方式 3:forEach 遍历方法(JDK8)
1. 方法定义
Collection 接口默认方法:default void forEach(Consumer<? super T> action)接收函数式接口 Consumer,遍历每个元素执行自定义操作。
2. Lambda 写法
import java.util.ArrayList;
public class ForEachMethodDemo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("苹果");
list.add("香蕉");
list.add("葡萄");
// lambda表达式
list.forEach(s -> System.out.println(s));
}
}
五、本篇统一小结
- 单列集合通用三种遍历:迭代器 Iterator、增强 for 循环、forEach 方法;
- Set 无索引,只能用这三种;List 额外支持普通 for、ListIterator;
- 迭代器依靠 cursor 指针遍历,hasNext 判断、next 取值并移动指针;
- 增强 for 底层是迭代器,语法最简,仅做遍历;
- forEach 是 JDK8 函数式遍历,配合 Lambda 简化代码;
- 遍历集合时,不要多次调用 next (),避免异常。