内部迭代与外部迭代
| 考量因素 | 推荐外部迭代 | 推荐内部迭代 |
|---|---|---|
| 代码简洁性 | ❌ 需要更多代码 | ✅ 更简洁 |
| 可读性 | ❌ 业务逻辑分散 | ✅ 声明式,更清晰 |
| 并行化 | ❌ 困难,需要手动实现 | ✅ 简单,.parallelStream() |
| 性能控制 | ✅ 完全控制,可手动优化 | ❌ 由JVM控制 |
| 复杂控制流 | ✅ 灵活(break、continue) | ❌ 有限制 |
| 修改集合 | ✅ 可直接修改 | ❌ 不能修改源集合 |
| 异常处理 | ✅ 精细控制 | ❌ 相对困难 |
| 函数式风格 | ❌ 命令式 | ✅ 函数式 |
场景
| 场景 | 推荐 | 原因 |
|---|---|---|
| 简单遍历 | 外部迭代(for-each) | 更直接 |
| 数据转换 | 内部迭代(Stream) | 更简洁 |
| 并行处理 | 内部迭代(parallelStream) | 更简单 |
| 复杂业务逻辑 | 内部迭代 | 更清晰 |
| 性能关键 | 根据情况选择 | 需要测试 |
内部迭代
遍历将在集合内部进行,我们不会显式地去控制这个循环
java
// 外部迭代(传统方式 - 命令式编程)
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> result = new ArrayList<>();
// 程序员显式控制迭代过程
for (String name : names) { // 1. 程序员控制迭代
if (name.startsWith("A")) { // 2. 程序员处理业务逻辑
result.add(name.toUpperCase());
}
}
// 问题:业务逻辑和迭代逻辑混杂在一起
// 内部迭代(Stream - 声明式编程)
List<String> result = names.stream() // 获取数据源
.filter(name -> name.startsWith("A")) // 做什么(业务逻辑)
.map(String::toUpperCase) // 做什么(业务逻辑)
.collect(Collectors.toList()); // 得到结果
// Stream API 控制迭代过程,程序员只关心业务逻辑
// 不好:多次终端操作
long count = list.stream().filter(condition).count();
List<T> filtered = list.stream().filter(condition).collect(toList());
// 好:一次终端操作
List<T> filtered = list.stream()
.filter(condition)
.collect(toList());
long count = filtered.size();
// 不好:昂贵的中间操作
stream.sorted().filter(condition).findFirst();
// 好:先过滤再排序
stream.filter(condition).sorted().findFirst();外部迭代
外部迭代指程序员直接控制迭代过程,显式地使用循环结构(如 for、while)来遍历集合元素。
java
// 外部迭代的典型形式
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 程序员控制迭代过程
for (int i = 0; i < names.size(); i++) { // 控制索引
String name = names.get(i); // 获取元素
System.out.println(name); // 处理元素
}
// 或使用增强for循环
for (String name : names) { // 控制遍历
System.out.println(name); // 处理元素
}
// 或使用迭代器
Iterator<String> iterator = names.iterator(); // 获取迭代器
while (iterator.hasNext()) { // 控制迭代
String name = iterator.next(); // 获取并处理
System.out.println(name);
}
朔风