Java 实例 – 集合遍历(超详细)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

一、前言

在 Java 开发中,集合遍历是一个基础但至关重要的操作。无论是处理用户数据、解析配置文件,还是构建复杂的业务逻辑,开发者都需要频繁地与集合(如 ArrayListHashMap 等)进行交互。然而,如何高效、安全地遍历集合,却常常成为开发者容易忽视的细节。本文将通过 Java 实例 – 集合遍历 的角度,结合代码示例和实际场景,逐步解析不同遍历方法的原理、使用场景及潜在陷阱,帮助读者建立系统的认知框架。


二、基础概念回顾

1. 什么是集合遍历?

集合遍历的核心目标是 按顺序访问集合中的每一个元素。例如,遍历一个 ArrayList 获取所有用户信息,或遍历 HashMap 检索特定键值对。在 Java 中,遍历方式的选择直接影响代码的效率和安全性。

比喻
可以把集合想象成一个超市的货架,每个元素是货架上的商品。遍历的过程就像用扫描仪逐个扫描商品,记录它们的信息。不同遍历方式就像不同的扫描工具——有的需要手动逐个扫描(如普通 for 循环),有的能自动识别商品并快速处理(如 Stream API)。

2. 常见的集合类型

Java 中的集合框架(java.util)提供了多种实现类,如:

  • 列表(List):如 ArrayList,元素有序且可重复。
  • 集合(Set):如 HashSet,元素无序且不可重复。
  • 映射(Map):如 HashMap,存储键值对。

这些类型的遍历逻辑和限制各有不同,需要根据具体需求选择方法。


三、经典遍历方法详解

1. 普通 for 循环

这是最基础的遍历方式,适用于 已知索引顺序的集合(如 List)。

示例代码:遍历 ArrayList

List<String> fruits = new ArrayList<>(Arrays.asList("Apple", "Banana", "Orange"));  
for (int i = 0; i < fruits.size(); i++) {  
    System.out.println(fruits.get(i));  
}  

优点与缺点

  • 优点
    • 直观易懂,适合对索引敏感的场景(如修改元素位置)。
    • 性能较高,因直接通过索引访问。
  • 缺点
    • 不适用于无索引的集合(如 Set)。
    • 直接修改集合会引发异常:例如遍历过程中删除元素,会导致 ConcurrentModificationException

2. 增强型 for 循环(for-each)

Java 5 引入的语法糖,语法简洁,不依赖索引,但 无法直接修改元素或集合

示例代码:遍历 ArrayList

List<String> fruits = new ArrayList<>(Arrays.asList("Apple", "Banana", "Orange"));  
for (String fruit : fruits) {  
    System.out.println(fruit);  
}  

优点与缺点

  • 优点
    • 代码简洁,适合只读操作。
    • 支持所有实现了 Iterable 接口的集合(如 ListSet)。
  • 缺点
    • 无法在遍历时修改元素或集合(如删除元素)。
    • 无法获取元素的索引位置。

3. 迭代器(Iterator)

迭代器是 安全遍历 的关键工具,尤其适用于需要 在遍历时修改集合 的场景。

示例代码:遍历并删除元素

List<String> fruits = new ArrayList<>(Arrays.asList("Apple", "Banana", "Orange"));  
Iterator<String> iterator = fruits.iterator();  
while (iterator.hasNext()) {  
    String fruit = iterator.next();  
    if (fruit.equals("Banana")) {  
        iterator.remove(); // 安全删除元素  
    }  
}  

迭代器的核心方法

方法功能描述
hasNext()判断是否有下一个元素
next()获取下一个元素
remove()删除当前元素(需在 next() 后调用)

优点与缺点

  • 优点
    • 支持遍历过程中修改集合(如删除元素)。
    • 兼容所有实现了 Iterable 的集合。
  • 缺点
    • 语法较繁琐,需手动管理 iterator 对象。
    • 不支持添加元素(某些集合如 ArrayList 的迭代器不允许 add)。

四、进阶方法:Java 8 的 Stream API

Java 8 引入的 Stream API,通过 函数式编程 的方式简化了集合处理,尤其适合 批量操作并行计算

示例代码:筛选并打印元素

List<String> fruits = Arrays.asList("Apple", "Banana", "Orange");  
fruits.stream()  
    .filter(fruit -> fruit.startsWith("A")) // 筛选以"A"开头的元素  
    .forEach(System.out::println); // 打印结果  

关键特性

  • 惰性求值:只有在终端操作(如 forEach)时才执行计算。
  • 链式调用:支持 mapfilter 等中间操作的无缝衔接。
  • 并行处理:通过 .parallelStream() 实现多线程加速。

适用场景

  • 数据过滤、转换、聚合:如统计用户订单总金额。
  • 复杂逻辑的简化:例如,flatMap 处理嵌套集合。

五、常见陷阱与解决方案

1. 遍历时修改集合引发的异常

错误代码示例

List<String> list = new ArrayList<>(Arrays.asList("A", "B"));  
for (String s : list) {  
    if (s.equals("B")) {  
        list.remove(s); // 触发 ConcurrentModificationException  
    }  
}  

原因:增强型 for 循环内部使用迭代器,直接修改集合会破坏迭代器的索引状态。

解决方案

  • 使用 迭代器的 remove() 方法(如前文示例)。
  • 将元素存入临时列表后批量删除:
    List<String> toRemove = new ArrayList<>();  
    for (String s : list) {  
        if (s.equals("B")) {  
            toRemove.add(s);  
        }  
    }  
    list.removeAll(toRemove);  
    

2. 并发修改与线程安全

若集合在多线程环境下被遍历和修改,需使用线程安全的集合(如 CopyOnWriteArrayList)。


六、性能对比与选择建议

遍历方式适用场景性能特点
普通 for 循环需索引操作或性能敏感场景快,但风险较高
增强型 for只读操作简单,但无法修改集合
迭代器需要遍历中修改元素灵活,需手动管理
Stream API复杂数据处理或并行计算代码简洁,但开销略高

选择建议

  • 基础场景:优先使用增强型 for 循环或普通 for
  • 修改集合:必须使用迭代器或 StreamremoveIf() 方法。
  • 复杂操作:结合 Stream 实现函数式编程范式。

七、总结

本文通过 Java 实例 – 集合遍历 的角度,系统梳理了遍历的核心方法、陷阱及优化策略。开发者需根据具体场景选择遍历方式:

  • 若需 高效访问索引,普通 for 循环是首选;
  • 若需 安全修改集合,迭代器是唯一合法途径;
  • 若需 简化复杂逻辑Stream API 提供了函数式编程的优雅解决方案。

掌握这些方法不仅能提升代码质量,更能为后续学习多线程、数据处理等高级主题打下坚实基础。实践时,建议读者通过编写实际案例(如统计订单金额、过滤用户列表)加深理解,逐步形成自己的“遍历工具箱”。

最新发布