杰瑞科技汇

collection 遍历 java

下面我将从 Java 8 之前Java 8 及以后,为你详细介绍各种遍历方式,并提供代码示例和优缺点分析。

collection 遍历 java-图1
(图片来源网络,侵删)

核心概念:Iterable 接口

你需要知道,Java 中的所有集合框架类(如 List, Set, Queue)都实现了 java.lang.Iterable 接口,这个接口是能够使用 for-each 循环(也称为增强 for 循环)的根本原因,因为它定义了一个 iterator() 方法。


Java 8 之前的遍历方式

经典的 for 循环 (索引遍历)

这种方式适用于所有实现了 List 接口的集合,因为 List 有索引。

适用场景:当你需要知道当前元素的索引,或者需要根据索引来访问/修改元素时。

代码示例 (以 ArrayList 为例):

collection 遍历 java-图2
(图片来源网络,侵删)
import java.util.ArrayList;
import java.util.List;
public class ForLoopExample {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        System.out.println("--- Classic For Loop ---");
        for (int i = 0; i < fruits.size(); i++) {
            String fruit = fruits.get(i);
            System.out.println("Index " + i + ": " + fruit);
            // 示例:修改元素
            if ("Banana".equals(fruit)) {
                fruits.set(i, "Mango");
            }
        }
        System.out.println("List after modification: " + fruits);
    }
}

优点

  • 可以通过索引 i 访问任意位置的元素。
  • 可以方便地在遍历过程中修改集合(通过 list.set(i, newValue))。
  • 性能通常很好,尤其是在 ArrayList 上。

缺点

  • 不适用于 SetQueue,因为它们没有 get(index) 方法,也没有固定的顺序。
  • 代码相对冗长。

迭代器 遍历

这是最通用、最安全的遍历方式,适用于所有 Iterable 对象(即所有集合)。

适用场景

collection 遍历 java-图3
(图片来源网络,侵删)
  • 当你需要遍历任何类型的集合(List, Set, Queue 等)。
  • 当你需要在遍历过程中安全地删除元素时。

代码示例:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorExample {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        System.out.println("\n--- Iterator Example ---");
        Iterator<String> iterator = fruits.iterator();
        while (iterator.hasNext()) {
            String fruit = iterator.next();
            System.out.println("Fruit: " + fruit);
            // 示例:安全地删除元素
            if ("Banana".equals(fruit)) {
                iterator.remove(); // 使用迭代器的 remove() 方法,而不是集合的 remove()
            }
        }
        System.out.println("List after removal: " + fruits);
    }
}

优点

  • 通用性强:适用于任何 Collection
  • 线程安全:在单线程环境下,如果使用迭代器自身的 remove() 方法,可以安全地删除当前元素,避免 ConcurrentModificationException(并发修改异常)。
  • 代码清晰。

缺点

  • 代码比 for-each 循环稍显繁琐。

重要提示:在遍历集合时,绝对不要使用 collection.remove() 来删除元素,这几乎肯定会抛出 ConcurrentModificationException,必须使用 iterator.remove()


增强 for 循环 (For-Each Loop)

这是 Java 5 引入的语法糖,极大地简化了遍历代码。

适用场景

  • 当你只需要读取集合中的元素,而不需要修改集合或获取索引时。
  • 这是最常用、最推荐的遍历方式。

代码示例:

import java.util.ArrayList;
import java.util.List;
public class ForEachExample {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        System.out.println("\n--- For-Each Loop ---");
        for (String fruit : fruits) {
            System.out.println("Fruit: " + fruit);
            // 注意:这里不能使用 fruit.remove() 或 fruit.add(),会抛出 ConcurrentModificationException
        }
    }
}

优点

  • 代码简洁、易读、不易出错。
  • 底层是基于迭代器实现的,所以同样适用于所有 Collection

缺点

  • 无法获取索引
  • 不能在遍历过程中安全地修改集合,如果你在循环体内尝试调用集合的 add()remove() 方法,会抛出 ConcurrentModificationException
  • 不能灵活地删除元素(不像迭代器那样有 remove() 方法)。

Java 8 及以后的遍历方式 (函数式编程)

Java 8 引入了 Stream API 和 Lambda 表达式,为集合遍历带来了革命性的变化,使代码更加声明式和简洁。

forEach + Lambda 表达式 / 方法引用

这是 Iterable 接口在 Java 8 中新增的默认方法,可以直接在集合对象上调用。

适用场景

  • 当你只想对集合中的每个元素执行一个操作(如打印、计算等),而不需要修改集合本身时。

代码示例:

import java.util.ArrayList;
import java.util.List;
public ForEachLambdaExample {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        System.out.println("\n--- ForEach with Lambda ---");
        // 使用 Lambda 表达式
        fruits.forEach(fruit -> System.out.println("Fruit: " + fruit));
        System.out.println("\n--- ForEach with Method Reference ---");
        // 使用方法引用 (更简洁)
        fruits.forEach(System.out::println);
    }
}

优点

  • 代码非常简洁,一行搞定。
  • 声明式风格,代码意图清晰(“对每个元素执行...操作”)。

缺点

  • 不能修改集合本身(不能增删元素)。
  • 如果需要处理元素,不能使用 continuebreak 语句来中断循环。

Stream API + forEach

这是最强大、最灵活的遍历方式,它将集合转换为一个“流”,可以对流进行各种操作。

适用场景

  • 当你需要对集合进行过滤、映射、排序、聚合等复杂操作时。
  • 当你需要并行处理以提高性能时。

代码示例:

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class StreamExample {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        fruits.add("Grape");
        System.out.println("\n--- Stream API Example ---");
        // 1. 过滤:只找出长度大于5的,并打印
        System.out.println("Fruits with length > 5:");
        fruits.stream()
              .filter(fruit -> fruit.length() > 5)
              .forEach(System.out::println); // 输出: Orange, Grape
        // 2. 转换:将所有水果名转换为大写,并收集到一个新列表中
        List<String> upperCaseFruits = fruits.stream()
                                            .map(String::toUpperCase)
                                            .collect(Collectors.toList());
        System.out.println("\nUppercase fruits: " + upperCaseFruits);
        // 3. 排序并遍历
        System.out.println("\nFruits sorted alphabetically:");
        fruits.stream()
              .sorted()
              .forEach(System.out::println); // 输出: Apple, Banana, Grape, Orange
    }
}

优点

  • 功能极其强大:支持链式调用,可以组合复杂的操作。
  • 易于并行化:只需将 stream() 换成 parallelStream(),就可以轻松实现多线程处理,充分利用多核 CPU。
  • 代码非常简洁且富有表现力

缺点

  • 对于非常简单的遍历(仅仅是打印),可能会显得有点“杀鸡用牛刀”。
  • 如果处理逻辑非常复杂,可读性可能会下降。

总结与最佳实践

遍历方式 适用场景 优点 缺点
经典 for 循环 List 遍历,需要索引或修改元素 可访问索引,性能好 不适用于 Set/Queue,代码冗长
迭代器 通用遍历,安全删除元素 通用,线程安全(单线程下) 代码稍显繁琐
增强 for 循环 最常用,仅读取元素 简洁,易读,通用 无法获取索引,不能修改集合
forEach + Lambda 最常用,仅读取元素并执行操作 极其简洁,声明式 不能修改集合,无法 break/continue
Stream API 复杂操作(过滤、映射、并行) 功能强大,易于并行,代码优雅 简单场景可能过重,复杂逻辑可读性待考

如何选择?

  1. 如果只是简单地遍历并打印或处理每个元素

    • 首选 增强 for 循环forEach + Lambda
    • 现代 Java 项目中,forEach + 方法引用 (list.forEach(System.out::println)) 是最优雅的选择。
  2. 如果你需要遍历 List 并且需要知道当前元素的索引

    • 使用 经典 for 循环
  3. 如果你需要在遍历过程中安全地删除元素

    • 使用 迭代器remove() 方法。
  4. 如果你需要对集合进行复杂的转换、过滤或聚合操作

    • 使用 Stream API
  5. 如果你需要并行处理集合以提高性能

    • 使用 Stream APIparallelStream()
分享:
扫描分享到社交APP
上一篇
下一篇