杰瑞科技汇

java arraylist 遍历

一个示例 ArrayList

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

java arraylist 遍历-图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("Mango");
    }
}

我们开始介绍四种遍历方法。


经典 for 循环(索引遍历)

这是最传统、最基础的遍历方式,通过索引来访问列表中的每一个元素。

代码示例

List<String> fruits = new ArrayList<>();
// ... (添加元素)
System.out.println("--- 方法一:经典 for 循环 ---");
for (int i = 0; i < fruits.size(); i++) {
    String fruit = fruits.get(i);
    System.out.println(fruit);
}

优点

  1. 直观易懂:对于初学者来说,这种写法最容易理解。
  2. 随机访问:可以在循环体内方便地通过索引 i 访问任意位置的元素,fruits.get(i + 1)
  3. 性能:在早期 Java 版本中,这种方式被认为是性能最高的,因为 ArrayList 底层是基于数组实现的,通过索引访问非常快。

缺点

  1. 代码冗长:需要声明索引变量 i,并编写循环条件 i < fruits.size() 和递增语句 i++,代码不够简洁。
  2. 不适用于所有 List:如果将 ArrayList 换成 LinkedListget(i) 操作的性能会非常差(需要遍历链表),此时这种方式就不合适了。

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

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

代码示例

List<String> fruits = new ArrayList<>();
// ... (添加元素)
System.out.println("\n--- 方法二:增强 for 循环 ---");
for (String fruit : fruits) {
    System.out.println(fruit);
}

优点

  1. 代码简洁:无需关心索引,语法非常清晰,可读性高。
  2. 类型安全:编译器会检查集合中的元素类型是否与声明的变量类型(这里是 String)匹配。
  3. 适用于所有 Iterable:任何实现了 Iterable 接口的集合(包括 ArrayList, LinkedList, HashSet 等)都可以使用这种方式。

缺点

  1. 无法获取索引:如果需要在遍历过程中知道当前元素的索引,此方法无能为力。
  2. 无法修改集合:在遍历过程中,不能安全地使用 remove() 方法删除元素(除非使用迭代器的 remove() 方法,见方法四)。
  3. 性能:在底层,它实际上是通过迭代器实现的,对于 ArrayList 其性能可能略低于经典的 for 循环,但差距微乎其微,通常可以忽略不计。

使用 Iterator(迭代器)

Iterator 是 Java 集合框架中专门用于遍历元素的接口,它是“安全”遍历的保证,尤其是在需要修改集合时。

java arraylist 遍历-图2
(图片来源网络,侵删)

代码示例

List<String> fruits = new ArrayList<>();
// ... (添加元素)
System.out.println("\n--- 方法三:使用 Iterator ---");
// 获取迭代器
java.util.Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
    String fruit = iterator.next();
    System.out.println(fruit);
    // 示例:在遍历时安全地删除元素
    // if ("Orange".equals(fruit)) {
    //     iterator.remove(); // 使用迭代器的 remove() 方法
    // }
}

优点

  1. 线程安全(相对)Iterator 提供了一种标准的、安全的方式来遍历集合,即使在单线程环境下,也能保证遍历过程的正确性。
  2. 安全的删除操作:这是它最大的优点,如果在遍历过程中需要删除元素,必须使用 iterator.remove() 方法,直接在集合上调用 list.remove() 会抛出 ConcurrentModificationException 异常。
  3. 通用性:所有集合都支持迭代器。

缺点

  1. 代码稍显繁琐:相比 For-Each 循环,需要多写几行代码来获取迭代器和编写 while 循环。
  2. 无法获取索引:同样,无法直接获取当前元素的索引。

Java 8+ Stream API

这是 Java 8 引入的函数式编程方式,功能非常强大,不仅能遍历,还能进行复杂的链式操作(如过滤、映射、聚合等)。

代码示例

List<String> fruits = new ArrayList<>();
// ... (添加元素)
System.out.println("\n--- 方法四:Java 8+ Stream API ---");
// 1. 简单遍历(消费)
fruits.stream().forEach(fruit -> System.out.println(fruit));
// 2. 更简洁的遍历(方法引用)
System.out.println("\n使用方法引用:");
fruits.stream().forEach(System.out::println);
// 3. 带条件的遍历(只打印长度大于 5 的水果)
System.out.println("\n只打印长度大于 5 的水果:");
fruits.stream()
      .filter(fruit -> fruit.length() > 5)
      .forEach(System.out::println);

优点

  1. 功能强大:不仅仅是遍历,可以无缝衔接 filter(), map(), sorted(), collect() 等各种操作,实现复杂的数据处理逻辑。
  2. 代码简洁(函数式风格):对于复杂的操作,使用 Lambda 表达式和方法引用可以使代码非常简洁和富有表现力。
  3. 并行处理:只需将 stream() 换成 parallelStream(),即可轻松实现多线程并行处理,提高大数据量下的处理速度。

缺点

  1. 学习成本:对于不熟悉函数式编程的开发者来说,需要一定的学习曲线。
  2. 性能开销:对于简单的遍历任务,Stream API 会引入一定的额外开销(如创建流、Lambda 表达式调用等),其性能可能不如传统的 For-Each 或经典 for 循环。
  3. 修改集合困难:Stream API 本身设计为“管道-过滤器”模式,主要用于数据转换和消费,而不是修改源集合。

总结与最佳实践

方法 优点 缺点 适用场景
经典 for 循环 直观,支持随机访问 代码冗长,不适用于 LinkedList 需要索引或随机访问元素的简单遍历。
增强 for 循环 代码简洁,可读性高,通用性强 无法获取索引,不能安全删除 绝大多数情况下的首选,简单、干净、高效。
Iterator 可以安全删除元素,通用性强 代码稍显繁琐,无法获取索引 需要在遍历过程中删除元素时,必须使用
Stream API 功能极其强大,支持并行和函数式操作 学习成本高,简单遍历有性能开销 复杂的数据处理、转换、聚合操作;需要并行计算时。

如何选择?

  1. 日常遍历,只读或修改元素:直接使用 增强 for 循环 (For-Each),这是最常用、最推荐的写法。

    for (String fruit : fruits) {
        // do something
    }
  2. 需要在遍历时删除元素:必须使用 Iterator

    Iterator<String> it = fruits.iterator();
    while (it.hasNext()) {
        String fruit = it.next();
        if (shouldRemove(fruit)) {
            it.remove(); // 安全删除
        }
    }
  3. 需要知道元素的索引:使用 经典 for 循环

    java arraylist 遍历-图3
    (图片来源网络,侵删)
    for (int i = 0; i < fruits.size(); i++) {
        System.out.println("Index " + i + ": " + fruits.get(i));
    }
  4. 需要对集合进行复杂的操作(过滤、转换、统计等):使用 Stream API

    List<String> longFruits = fruits.stream()
                                    .filter(f -> f.length() > 5)
                                    .collect(Collectors.toList());
分享:
扫描分享到社交APP
上一篇
下一篇