Java中实现带序号遍历需外部维护计数器,推荐传统for循环(索引)、while循环或Stream+原子变量;封装为forEachWithIndex工具方法可提升复用性与可读性。

在 Java 中实现带序号的遍历,核心思路是:**让计数器脱离迭代器自身,由外部变量承载,并在每次循环中显式递增**。Java 的增强 for 循环(for (T item : collection))不暴露索引,因此不能直接用于序号计数;必须改用传统 for 循环、while 循环,或借助 Stream API 配合原子变量/包装类来安全维护状态。
用传统 for 循环 + 索引变量(最直观)
适用于 List 或其他支持随机访问的集合,直接利用下标作为序号(从 0 或 1 开始):
- 序号从 1 开始(更符合“第1个、第2个”的语义):
List<String> items = Arrays.asList("apple", "banana", "cherry");
for (int i = 0; i < items.size(); i++) {
String item = items.get(i);
int serialNumber = i + 1; // 序号 = 下标 + 1
System.out.println(serialNumber + ". " + item);
}
// 输出:
// 1. apple
// 2. banana
// 3. cherry
- 注意:避免在循环体中修改
items结构(如 remove/add),否则可能引发ConcurrentModificationException或逻辑错位。
用 while 循环 + 显式计数器(通用性强)
适合所有 Iterable(包括 Set、Map.values()、自定义迭代器等),不依赖随机访问能力:
Collection<String> items = new LinkedHashSet<>(Arrays.asList("x", "y", "z"));
Iterator<String> it = items.iterator();
int index = 0;
while (it.hasNext()) {
String item = it.next();
index++; // 每次取元素后立即递增,确保序号与当前元素严格对应
System.out.println(index + ": " + item);
}
- 关键点:计数器
index在it.next()后立即更新,保证序号顺序不因异常或提前退出而错乱。 - 若需跳过某些元素但仍保留原始序号(如“第3个元素被过滤”),则把
index++放到循环开头。
用 Stream API + AtomicInteger(适合函数式风格 & 并发安全场景)
当需要链式处理、过滤、映射,且希望保持序号连续时,可用 AtomicInteger 维护外部状态(注意:普通 int 在 lambda 中不可变,必须用原子类或数组):
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
List<String> items = Arrays.asList("a", "b", "c", "d");
AtomicInteger counter = new AtomicInteger(1);
items.stream()
.filter(s -> !s.equals("c")) // 过滤掉 "c"
.map(s -> counter.getAndIncrement() + ". " + s)
.forEach(System.out::println);
// 输出:
// 1. a
// 2. b
// 3. d
- 使用
getAndIncrement()可保证多线程下序号唯一不重复(单线程下也推荐,语义清晰)。 - ⚠️ 注意:Stream 是惰性求值,若中间有终止操作(如
findFirst())导致短路,计数器仍会按实际执行次数递增,序号反映的是“被处理的元素顺序”,而非原始位置。
封装为可复用工具方法(提升可读性与复用性)
将带序号遍历逻辑抽象成静态方法,隐藏计数细节:
public static <T> void forEachWithIndex(Collection<T> collection,
BiConsumer<Integer, T> action) {
int index = 0;
for (T item : collection) {
action.accept(++index, item); // 先递增再传入
}
}
// 使用示例:
List<String> list = Arrays.asList("hello", "world");
forEachWithIndex(list, (i, s) -> System.out.println(i + " → " + s));
// 输出:
// 1 → hello
// 2 → world
- 该方法兼容任意
Collection,调用方无需关心计数器管理,专注业务逻辑。 - 参数名
i明确代表“序号”,避免与数组下标混淆。
不复杂但容易忽略的是:序号语义必须与业务一致——是“处理顺序”还是“原始位置”?选对循环方式和计数时机,比单纯加个变量更重要。

















