杰瑞科技汇

ArrayList遍历Java有几种高效方式?

创建一个示例 ArrayList

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

ArrayList遍历Java有几种高效方式?-图1
(图片来源网络,侵删)
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);
}

优点

  1. 直观易懂:对于初学者来说,这种方式最容易理解。
  2. 随机访问:如果你需要在遍历过程中通过索引访问特定位置的元素,或者需要根据索引进行某些操作,这种方式非常方便。

缺点

  1. 代码冗长:相比其他方法,需要编写更多的模板代码(初始化 i,条件 i < size(),递增 i++)。
  2. 性能稍差:对于 LinkedList 这种不支持快速随机访问的集合,get(i) 方法的时间复杂度是 O(n),会导致整个遍历过程变为 O(n²),虽然对于 ArrayList get(i) 是 O(1) 性能很好,但这种写法不具有通用性。

增强 for 循环(For-Each 循环)

这是 Java 5 引入的一种语法糖,专门用于遍历集合和数组,代码更简洁。

代码示例

System.out.println("\n--- 方法二:增强 for 循环 ---");
for (String fruit : fruits) {
    System.out.println("水果: " + fruit);
}

优点

  1. 代码简洁:语法非常简单,可读性高。
  2. 不易出错:无需关心索引的边界和递增,减少了出错的可能性。
  3. 性能好:对于 ArrayList,其内部实现和索引遍历性能几乎一样,对于 LinkedList,它使用迭代器,性能是 O(n),是最佳选择。

缺点

  1. 无法获取索引:如果你需要知道当前元素的索引位置,这种方法就无能为力了。
  2. 无法在遍历过程中修改集合:如果你尝试在循环内部添加或删除元素(除了通过迭代器自身的 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);

优点

  1. 安全删除元素:这是迭代器最重要的功能,在遍历时使用 iterator.remove() 方法可以安全地删除当前元素,而不会抛出并发修改异常。
  2. 通用性强:所有集合都实现了 Iterator 接口,因此这是一种通用的遍历方式。

缺点

  1. 代码稍显繁琐:相比 For-Each 循环,需要多写几行代码来获取迭代器和判断 hasNext()

Java 8+ Stream API (流式处理)

这是 Java 8 引入的一种现代、函数式的处理集合的方式,它不仅仅用于遍历,更侧重于对集合进行复杂的转换、过滤、聚合等操作。

ArrayList遍历Java有几种高效方式?-图2
(图片来源网络,侵删)

代码示例

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));

优点

  1. 代码极其简洁和声明式:特别是结合 Lambda 表达式,代码非常优雅,专注于“做什么”而不是“怎么做”。
  2. 功能强大:可以轻松实现复杂的链式操作,如 filter(), map(), sorted(), reduce() 等。
  3. 易于并行化:只需将 stream() 换成 parallelStream(),就可以轻松地将操作并行化,提升大数据量下的处理速度。

缺点

  1. 学习曲线:对于不熟悉函数式编程和 Lambda 表达式的开发者来说,可能需要一些时间来适应。
  2. 性能开销:对于非常简单的遍历任务,Stream API 可能会引入一些额外的开销(如创建流管道),性能可能不如传统的 For-Each 循环,但对于复杂操作,其性能优势(尤其是并行流)非常明显。

总结与如何选择

方法 优点 缺点 适用场景
经典 for 循环 直观,支持随机访问 代码冗长,对非 ArrayList 性能差 需要索引,或需要修改集合结构(非删除)时。
增强 for 循环 代码简洁,不易出错,性能好 无法获取索引,不能安全删除 日常遍历的首选,绝大多数情况下,只需要读取元素时使用。
迭代器 唯一能安全删除的遍历方式 代码稍显繁琐 需要在遍历过程中删除元素时,这是唯一安全的选择。
Stream API 代码优雅,功能强大,易于并行化 学习成本高,简单遍历有性能开销 需要对集合进行复杂的转换、过滤、聚合等函数式操作时。

  • 只是想简单地打印或读取所有元素? -> 使用 增强 for 循环,这是最常用、最平衡的选择。
  • 需要在遍历过程中删除某个元素? -> 使用 迭代器
  • 需要根据索引进行操作? -> 使用 经典 for 循环
  • 需要对数据进行复杂的计算、转换或过滤? -> 使用 Stream API
ArrayList遍历Java有几种高效方式?-图3
(图片来源网络,侵删)
分享:
扫描分享到社交APP
上一篇
下一篇