创建一个示例 ArrayList
我们创建一个 ArrayList 并添加一些元素,以便在下面的示例中使用。

import java.util.ArrayList;
import java.util.List;
public class ArrayListTraversal {
public static void main(String[] args) {
// 创建一个 String 类型的 ArrayList
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
fruits.add("Grape");
fruits.add("Mango");
System.out.println("原始 ArrayList: " + fruits);
}
}
经典的 for 循环(索引遍历)
这是最传统、最基础的方法,通过索引来访问每一个元素。
代码示例
System.out.println("\n--- 方法一:经典 for 循环 ---");
for (int i = 0; i < fruits.size(); i++) {
String fruit = fruits.get(i);
System.out.println("水果: " + fruit);
}
优点
- 直观易懂:对于初学者来说,这种方式最容易理解。
- 随机访问:如果你需要在遍历过程中通过索引访问特定位置的元素,或者需要根据索引进行某些操作,这种方式非常方便。
缺点
- 代码冗长:相比其他方法,需要编写更多的模板代码(初始化
i,条件i < size(),递增i++)。 - 性能稍差:对于
LinkedList这种不支持快速随机访问的集合,get(i)方法的时间复杂度是 O(n),会导致整个遍历过程变为 O(n²),虽然对于ArrayListget(i)是 O(1) 性能很好,但这种写法不具有通用性。
增强 for 循环(For-Each 循环)
这是 Java 5 引入的一种语法糖,专门用于遍历集合和数组,代码更简洁。
代码示例
System.out.println("\n--- 方法二:增强 for 循环 ---");
for (String fruit : fruits) {
System.out.println("水果: " + fruit);
}
优点
- 代码简洁:语法非常简单,可读性高。
- 不易出错:无需关心索引的边界和递增,减少了出错的可能性。
- 性能好:对于
ArrayList,其内部实现和索引遍历性能几乎一样,对于LinkedList,它使用迭代器,性能是 O(n),是最佳选择。
缺点
- 无法获取索引:如果你需要知道当前元素的索引位置,这种方法就无能为力了。
- 无法在遍历过程中修改集合:如果你尝试在循环内部添加或删除元素(除了通过迭代器自身的
remove()方法),会抛出ConcurrentModificationException异常。
使用迭代器 (Iterator)
迭代器是 Java 集合框架的一部分,它提供了一种标准的方式来遍历集合,并且可以在遍历过程中安全地删除元素。
代码示例
System.out.println("\n--- 方法三:使用迭代器 ---");
// 获取迭代器
java.util.Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println("水果: " + fruit);
// 示例:如果水果是 "Orange",就把它从集合中删除
// 注意:必须使用 iterator.remove(),而不是 fruits.remove()
if ("Orange".equals(fruit)) {
iterator.remove(); // 安全删除
System.out.println("(已删除 Orange)");
}
}
System.out.println("删除后的 ArrayList: " + fruits);
优点
- 安全删除元素:这是迭代器最重要的功能,在遍历时使用
iterator.remove()方法可以安全地删除当前元素,而不会抛出并发修改异常。 - 通用性强:所有集合都实现了
Iterator接口,因此这是一种通用的遍历方式。
缺点
- 代码稍显繁琐:相比 For-Each 循环,需要多写几行代码来获取迭代器和判断
hasNext()。
Java 8+ Stream API (流式处理)
这是 Java 8 引入的一种现代、函数式的处理集合的方式,它不仅仅用于遍历,更侧重于对集合进行复杂的转换、过滤、聚合等操作。

代码示例
System.out.println("\n--- 方法四:Java 8 Stream API ---");
// 1. 简单遍历(消费)
System.out.println("--- 简单遍历 ---");
fruits.stream().forEach(fruit -> System.out.println("水果: " + fruit));
// 2. 带过滤的遍历
System.out.println("\n--- 带过滤的遍历(只输出长度大于5的水果)---");
fruits.stream()
.filter(fruit -> fruit.length() > 5) // 过滤条件
.forEach(fruit -> System.out.println("水果: " + fruit));
// 3. 并行遍历(利用多核CPU加速)
System.out.println("\n--- 并行遍历 ---");
fruits.parallelStream().forEach(fruit -> System.out.println("水果: " + fruit));
优点
- 代码极其简洁和声明式:特别是结合 Lambda 表达式,代码非常优雅,专注于“做什么”而不是“怎么做”。
- 功能强大:可以轻松实现复杂的链式操作,如
filter(),map(),sorted(),reduce()等。 - 易于并行化:只需将
stream()换成parallelStream(),就可以轻松地将操作并行化,提升大数据量下的处理速度。
缺点
- 学习曲线:对于不熟悉函数式编程和 Lambda 表达式的开发者来说,可能需要一些时间来适应。
- 性能开销:对于非常简单的遍历任务,Stream API 可能会引入一些额外的开销(如创建流管道),性能可能不如传统的 For-Each 循环,但对于复杂操作,其性能优势(尤其是并行流)非常明显。
总结与如何选择
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 经典 for 循环 | 直观,支持随机访问 | 代码冗长,对非 ArrayList 性能差 |
需要索引,或需要修改集合结构(非删除)时。 |
| 增强 for 循环 | 代码简洁,不易出错,性能好 | 无法获取索引,不能安全删除 | 日常遍历的首选,绝大多数情况下,只需要读取元素时使用。 |
| 迭代器 | 唯一能安全删除的遍历方式 | 代码稍显繁琐 | 需要在遍历过程中删除元素时,这是唯一安全的选择。 |
| Stream API | 代码优雅,功能强大,易于并行化 | 学习成本高,简单遍历有性能开销 | 需要对集合进行复杂的转换、过滤、聚合等函数式操作时。 |
- 只是想简单地打印或读取所有元素? -> 使用 增强 for 循环,这是最常用、最平衡的选择。
- 需要在遍历过程中删除某个元素? -> 使用 迭代器。
- 需要根据索引进行操作? -> 使用 经典 for 循环。
- 需要对数据进行复杂的计算、转换或过滤? -> 使用 Stream API。

