下面我将从 Java 8 之前 到 Java 8 及以后,为你详细介绍各种遍历方式,并提供代码示例和优缺点分析。

核心概念:Iterable 接口
你需要知道,Java 中的所有集合框架类(如 List, Set, Queue)都实现了 java.lang.Iterable 接口,这个接口是能够使用 for-each 循环(也称为增强 for 循环)的根本原因,因为它定义了一个 iterator() 方法。
Java 8 之前的遍历方式
经典的 for 循环 (索引遍历)
这种方式适用于所有实现了 List 接口的集合,因为 List 有索引。
适用场景:当你需要知道当前元素的索引,或者需要根据索引来访问/修改元素时。
代码示例 (以 ArrayList 为例):

import java.util.ArrayList;
import java.util.List;
public class ForLoopExample {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
System.out.println("--- Classic For Loop ---");
for (int i = 0; i < fruits.size(); i++) {
String fruit = fruits.get(i);
System.out.println("Index " + i + ": " + fruit);
// 示例:修改元素
if ("Banana".equals(fruit)) {
fruits.set(i, "Mango");
}
}
System.out.println("List after modification: " + fruits);
}
}
优点:
- 可以通过索引
i访问任意位置的元素。 - 可以方便地在遍历过程中修改集合(通过
list.set(i, newValue))。 - 性能通常很好,尤其是在
ArrayList上。
缺点:
- 不适用于
Set和Queue,因为它们没有get(index)方法,也没有固定的顺序。 - 代码相对冗长。
迭代器 遍历
这是最通用、最安全的遍历方式,适用于所有 Iterable 对象(即所有集合)。
适用场景:

- 当你需要遍历任何类型的集合(
List,Set,Queue等)。 - 当你需要在遍历过程中安全地删除元素时。
代码示例:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorExample {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
System.out.println("\n--- Iterator Example ---");
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println("Fruit: " + fruit);
// 示例:安全地删除元素
if ("Banana".equals(fruit)) {
iterator.remove(); // 使用迭代器的 remove() 方法,而不是集合的 remove()
}
}
System.out.println("List after removal: " + fruits);
}
}
优点:
- 通用性强:适用于任何
Collection。 - 线程安全:在单线程环境下,如果使用迭代器自身的
remove()方法,可以安全地删除当前元素,避免ConcurrentModificationException(并发修改异常)。 - 代码清晰。
缺点:
- 代码比 for-each 循环稍显繁琐。
重要提示:在遍历集合时,绝对不要使用
collection.remove()来删除元素,这几乎肯定会抛出ConcurrentModificationException,必须使用iterator.remove()。
增强 for 循环 (For-Each Loop)
这是 Java 5 引入的语法糖,极大地简化了遍历代码。
适用场景:
- 当你只需要读取集合中的元素,而不需要修改集合或获取索引时。
- 这是最常用、最推荐的遍历方式。
代码示例:
import java.util.ArrayList;
import java.util.List;
public class ForEachExample {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
System.out.println("\n--- For-Each Loop ---");
for (String fruit : fruits) {
System.out.println("Fruit: " + fruit);
// 注意:这里不能使用 fruit.remove() 或 fruit.add(),会抛出 ConcurrentModificationException
}
}
}
优点:
- 代码简洁、易读、不易出错。
- 底层是基于迭代器实现的,所以同样适用于所有
Collection。
缺点:
- 无法获取索引。
- 不能在遍历过程中安全地修改集合,如果你在循环体内尝试调用集合的
add()或remove()方法,会抛出ConcurrentModificationException。 - 不能灵活地删除元素(不像迭代器那样有
remove()方法)。
Java 8 及以后的遍历方式 (函数式编程)
Java 8 引入了 Stream API 和 Lambda 表达式,为集合遍历带来了革命性的变化,使代码更加声明式和简洁。
forEach + Lambda 表达式 / 方法引用
这是 Iterable 接口在 Java 8 中新增的默认方法,可以直接在集合对象上调用。
适用场景:
- 当你只想对集合中的每个元素执行一个操作(如打印、计算等),而不需要修改集合本身时。
代码示例:
import java.util.ArrayList;
import java.util.List;
public ForEachLambdaExample {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
System.out.println("\n--- ForEach with Lambda ---");
// 使用 Lambda 表达式
fruits.forEach(fruit -> System.out.println("Fruit: " + fruit));
System.out.println("\n--- ForEach with Method Reference ---");
// 使用方法引用 (更简洁)
fruits.forEach(System.out::println);
}
}
优点:
- 代码非常简洁,一行搞定。
- 声明式风格,代码意图清晰(“对每个元素执行...操作”)。
缺点:
- 不能修改集合本身(不能增删元素)。
- 如果需要处理元素,不能使用
continue或break语句来中断循环。
Stream API + forEach
这是最强大、最灵活的遍历方式,它将集合转换为一个“流”,可以对流进行各种操作。
适用场景:
- 当你需要对集合进行过滤、映射、排序、聚合等复杂操作时。
- 当你需要并行处理以提高性能时。
代码示例:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
fruits.add("Grape");
System.out.println("\n--- Stream API Example ---");
// 1. 过滤:只找出长度大于5的,并打印
System.out.println("Fruits with length > 5:");
fruits.stream()
.filter(fruit -> fruit.length() > 5)
.forEach(System.out::println); // 输出: Orange, Grape
// 2. 转换:将所有水果名转换为大写,并收集到一个新列表中
List<String> upperCaseFruits = fruits.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println("\nUppercase fruits: " + upperCaseFruits);
// 3. 排序并遍历
System.out.println("\nFruits sorted alphabetically:");
fruits.stream()
.sorted()
.forEach(System.out::println); // 输出: Apple, Banana, Grape, Orange
}
}
优点:
- 功能极其强大:支持链式调用,可以组合复杂的操作。
- 易于并行化:只需将
stream()换成parallelStream(),就可以轻松实现多线程处理,充分利用多核 CPU。 - 代码非常简洁且富有表现力。
缺点:
- 对于非常简单的遍历(仅仅是打印),可能会显得有点“杀鸡用牛刀”。
- 如果处理逻辑非常复杂,可读性可能会下降。
总结与最佳实践
| 遍历方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 经典 for 循环 | List 遍历,需要索引或修改元素 |
可访问索引,性能好 | 不适用于 Set/Queue,代码冗长 |
| 迭代器 | 通用遍历,安全删除元素 | 通用,线程安全(单线程下) | 代码稍显繁琐 |
| 增强 for 循环 | 最常用,仅读取元素 | 简洁,易读,通用 | 无法获取索引,不能修改集合 |
forEach + Lambda |
最常用,仅读取元素并执行操作 | 极其简洁,声明式 | 不能修改集合,无法 break/continue |
| Stream API | 复杂操作(过滤、映射、并行) | 功能强大,易于并行,代码优雅 | 简单场景可能过重,复杂逻辑可读性待考 |
如何选择?
-
如果只是简单地遍历并打印或处理每个元素:
- 首选 增强 for 循环 或
forEach+ Lambda。 - 现代 Java 项目中,
forEach+ 方法引用 (list.forEach(System.out::println)) 是最优雅的选择。
- 首选 增强 for 循环 或
-
如果你需要遍历
List并且需要知道当前元素的索引:- 使用 经典 for 循环。
-
如果你需要在遍历过程中安全地删除元素:
- 使用 迭代器 的
remove()方法。
- 使用 迭代器 的
-
如果你需要对集合进行复杂的转换、过滤或聚合操作:
- 使用 Stream API。
-
如果你需要并行处理集合以提高性能:
- 使用 Stream API 的
parallelStream()。
- 使用 Stream API 的
