1. 概述

在日常开发中,我们经常需要从后往前遍历一个 List。本文将系统性地介绍几种在 Java 中实现反向遍历的常用方法,涵盖原生实现和主流第三方库方案,帮助你在不同场景下做出合适选择。

你会看到一些简单粗暴但高效的技巧,也会踩到一些容易忽略的坑 ❌,比如修改原集合这种副作用操作。

2. Java 中的 Iterator 简要回顾

Iterator 是 Java 集合框架中的核心接口之一,用于统一遍历集合元素。它自 Java 1.2 引入,取代了早期的 Enumeration

虽然 Iterator 本身只支持单向遍历(向前),但它的子接口 ListIterator 提供了双向能力,这正是我们实现反向遍历的关键 ✅。

3. 使用核心 Java 实现反向遍历

3.1. 倒序 for 循环

最直接的方式就是从 size - 1 开始递减索引,一路遍历到 0。

for (int i = list.size(); i-- > 0; ) {
    System.out.println(list.get(i));
}

✅ 优点:

  • 不依赖额外类库
  • 性能高,适合 ArrayList 这类支持随机访问的结构

⚠️ 注意:

  • i-- > 0 这个写法有点反直觉,但很经典 —— 先比较再自减,能正确访问 index = 0 的元素
  • 对 LinkedList 使用 get(i) 会很慢 ❌,因为每次都要从头遍历

3.2. 使用 ListIterator

ListIterator 支持双向遍历,是标准库中真正意义上的“反向迭代器”。

你可以通过传入 list.size() 来获取一个指向末尾的迭代器:

ListIterator<String> listIterator = list.listIterator(list.size());

然后调用 hasPrevious()previous() 方法进行反向遍历:

while (listIterator.hasPrevious()) {
    System.out.println(listIterator.previous());
}

✅ 优点:

  • 不改变原列表顺序
  • 对 LinkedList 友好,每次移动是 O(1)
  • 可双向移动,灵活性高

⚠️ 适用场景:

  • 需要边遍历边修改元素(如删除)时非常有用
  • 比倒序 for 更适合链表结构

3.3. 使用 Collections.reverse()

Collections 工具类提供了一个静态方法 reverse(),可以原地反转列表:

Collections.reverse(list);

反转后直接用增强 for 遍历即可:

for (String item : list) {
    System.out.println(item);
}

❌ 严重副作用:

  • 直接修改了原列表的顺序,可能影响后续逻辑
  • 如果你不希望改变原始数据,这是个大坑!

✅ 仅建议在以下情况使用:

  • 明确知道后续不会再用原顺序
  • 性能敏感且不在乎数据状态

4. 使用 Apache Commons 的 ReverseListIterator

Apache Commons Collections 提供了一个专门用于反向遍历的工具类:ReverseListIterator

首先引入依赖:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.1</version>
</dependency>

使用方式非常直观:

ReverseListIterator<String> reverseListIterator = new ReverseListIterator<>(list);
while (reverseListIterator.hasNext()) {
    System.out.println(reverseListIterator.next());
}

✅ 优点:

  • 语义清晰,代码可读性强
  • 不修改原列表
  • 内部封装了 ListIterator 的反向逻辑,使用更简单

⚠️ 注意:

  • 需要引入第三方依赖,轻量项目可权衡是否值得
  • next() 返回的是从后往前的下一个元素,逻辑上没问题但容易误解

5. 使用 Guava 的 Lists.reverse()

Google Guava 提供了更优雅的视图方式:Lists.reverse()

先加依赖:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

调用方式如下:

List<String> reversedList = Lists.reverse(list);
for (String item : reversedList) {
    System.out.println(item);
}

✅ 核心优势:

  • 返回的是原列表的反向视图(reverse view),不是副本
  • 修改 reversedList 会影响原列表,反之亦然(双向绑定)
  • 零拷贝,内存友好

⚠️ 特性说明:

  • 虽然返回类型是 List,但它只是一个包装视图
  • 适用于需要频繁切换正反向遍历的场景

6. 总结

方法 是否修改原列表 是否适合 LinkedList 是否需要第三方依赖
倒序 for 循环 ❌ 否 ❌ 差(O(n²)) ✅ 无
ListIterator ✅ 否 ✅ 好(O(1)) ✅ 无
Collections.reverse() ❌ 是(原地反转) ✅ 可用 ✅ 无
Apache ReverseListIterator ✅ 否 ✅ 好 ❌ 需要
Guava Lists.reverse() ✅ 否(仅视图) ✅ 好 ❌ 需要

📌 最佳实践建议:

  • ✅ **优先使用 ListIterator**:原生支持、高效、安全,适合绝大多数场景
  • ✅ 若已在用 Guava,推荐 Lists.reverse(),语义清晰且性能优秀
  • ✅ Apache 的 ReverseListIterator 也可考虑,但优先级略低
  • ❌ 尽量避免 Collections.reverse(),除非你真的想改原数据

所有示例代码和单元测试已整理至 GitHub:

https://github.com/baeldung/java-tutorials/tree/master/core-java-modules/core-java-collections-list


原始标题:Iterating Backward Through a List | Baeldung