Java 实例 – 集合遍历(实战指南)

Java 实例 – 集合遍历:从入门到精通的实战指南

在 Java 开发中,集合(Collection)是处理数据最常用的数据结构之一。无论是从数据库读取用户列表,还是处理配置项、日志记录,我们几乎每天都在与集合打交道。而集合的核心操作之一,就是遍历——也就是逐个访问集合中的每一个元素。

如果你刚接触 Java,可能会觉得“遍历”听起来很简单:for 循环不就能搞定?但随着项目复杂度上升,你会遇到并发修改异常、性能瓶颈、代码冗长等问题。这时候,掌握多种遍历方式,理解每种方式的适用场景,就变得至关重要。

本文将以实际代码为例,带你系统掌握 Java 实例 – 集合遍历 的各种方法,从基础到进阶,帮你写出更优雅、更安全、更高效的代码。


为什么要学习集合遍历?

想象一下你有一本厚厚的通讯录,里面记录了 1000 个联系人。现在你要找出所有姓“张”的人。如果逐个翻页查看,效率极低;但如果你能用“快速查找”功能,瞬间筛选出结果,那效率就高多了。

集合遍历的本质,就是“快速查找”工具的使用。不同的遍历方式,就像不同的查找工具。有的快但不能修改,有的灵活但容易出错。掌握它们,才能在开发中游刃有余。


1. for-each 循环:最简洁的遍历方式

for-each 循环(也叫增强 for 循环)是 Java 5 引入的语法糖,它让遍历集合变得极其简单。它是大多数初学者首选的方式。

代码示例:遍历 List

import java.util.ArrayList;
import java.util.List;

public class ForEachExample {
    public static void main(String[] args) {
        // 创建一个包含 5 个名字的列表
        List<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Charlie");
        names.add("Diana");
        names.add("Eve");

        // 使用 for-each 循环遍历集合
        for (String name : names) {
            System.out.println("当前名字:" + name);
        }
    }
}

中文注释说明

  • List<String> names:声明一个字符串类型的列表,用于存储名字。
  • names.add(...):向列表中添加元素。
  • for (String name : names):这是 for-each 循环语法,name 是当前元素的变量名,names 是被遍历的集合。
  • System.out.println(...):打印当前名字。

优点

  • 代码简洁,可读性强。
  • 避免手动索引操作,不容易出错。

缺点

  • 无法在遍历时修改集合(如删除元素),否则会抛出 ConcurrentModificationException

2. Iterator 迭代器:安全修改集合的利器

当你需要在遍历过程中删除或添加元素时,for-each 就会“罢工”,抛出异常。这时,Iterator 就派上用场了。

代码示例:使用 Iterator 删除偶数

import java.util.*;

public class IteratorExample {
    public static void main(String[] args) {
        // 创建一个整数列表
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        numbers.add(5);
        numbers.add(6);

        // 获取迭代器
        Iterator<Integer> iterator = numbers.iterator();

        // 使用 while 循环配合 Iterator
        while (iterator.hasNext()) {
            Integer num = iterator.next();  // 获取下一个元素

            // 如果是偶数,就删除
            if (num % 2 == 0) {
                iterator.remove();  // 安全删除当前元素
            }
        }

        // 输出结果
        System.out.println("删除偶数后的列表:" + numbers);
    }
}

中文注释说明

  • iterator.hasNext():判断是否还有下一个元素。
  • iterator.next():返回下一个元素并移动指针。
  • iterator.remove()唯一安全删除元素的方法,必须通过迭代器调用。

重要提醒

  • 不能在 for-each 中调用 remove(),否则会触发并发修改异常。
  • Iterator.remove() 是唯一合法的删除方式。

3. 传统 for 循环:索引控制的灵活性

当需要根据索引进行操作,比如访问前一个元素、跳过某些位置、或执行条件判断时,传统 for 循环就非常有优势。

代码示例:遍历 List 并访问前后元素

import java.util.*;

public class TraditionalForExample {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("苹果", "香蕉", "橙子", "葡萄", "草莓");

        // 使用传统 for 循环,通过索引遍历
        for (int i = 0; i < fruits.size(); i++) {
            String current = fruits.get(i);  // 获取当前元素
            String next = "";  // 声明下一个元素

            // 判断是否是最后一个元素
            if (i < fruits.size() - 1) {
                next = fruits.get(i + 1);  // 获取下一个元素
            } else {
                next = "无";
            }

            System.out.println("当前水果:" + current + ",下一个水果:" + next);
        }
    }
}

中文注释说明

  • fruits.size():获取集合长度。
  • fruits.get(i):通过索引获取元素,适用于 List。
  • i < fruits.size() - 1:防止索引越界。

适用场景

  • 需要访问前后元素。
  • 需要跳过某些索引(如每隔一个处理一次)。
  • 需要倒序遍历。

4. Stream API:函数式编程的优雅之选

Java 8 引入的 Stream API 让集合遍历进入函数式编程时代。它不只遍历,还能过滤、映射、聚合,代码更简洁、更强大。

代码示例:使用 Stream 筛选并打印名字长度大于 4 的人

import java.util.*;
import java.util.stream.Collectors;

public class StreamExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Diana", "Eve", "Frank");

        // 使用 Stream API 进行链式操作
        List<String> filteredNames = names.stream()
            .filter(name -> name.length() > 4)  // 筛选出长度大于 4 的名字
            .collect(Collectors.toList());     // 收集结果为列表

        // 遍历输出
        filteredNames.forEach(name -> System.out.println("名字:" + name));
    }
}

中文注释说明

  • stream():将集合转换为流。
  • filter(...):过滤条件,只保留满足条件的元素。
  • Collectors.toList():将流中的元素收集回列表。
  • forEach(...):遍历并执行操作。

优势

  • 支持链式调用,逻辑清晰。
  • 可并行处理(parallelStream()),适合大数据。
  • 代码更接近自然语言,可读性高。

5. Map 遍历:键值对的处理方式

Map 是键值对集合,遍历方式也更丰富。常见有三种方式:entrySet、keySet、forEach。

代码示例:遍历 Map 的三种方式

import java.util.*;

public class MapTraversalExample {
    public static void main(String[] args) {
        Map<String, Integer> scores = new HashMap<>();
        scores.put("张三", 85);
        scores.put("李四", 92);
        scores.put("王五", 78);

        // 方式一:使用 entrySet + for-each
        System.out.println("方式一:entrySet 遍历");
        for (Map.Entry<String, Integer> entry : scores.entrySet()) {
            System.out.println(entry.getKey() + " 的成绩是:" + entry.getValue());
        }

        // 方式二:使用 keySet + for-each
        System.out.println("\n方式二:keySet 遍历");
        for (String key : scores.keySet()) {
            System.out.println(key + " 的成绩是:" + scores.get(key));
        }

        // 方式三:使用 forEach + Lambda
        System.out.println("\n方式三:forEach + Lambda");
        scores.forEach((name, score) -> System.out.println(name + " 的成绩是:" + score));
    }
}

中文注释说明

  • entrySet():返回键值对集合,适合同时获取 key 和 value。
  • keySet():返回所有键的集合,适合只关心 key。
  • forEach(...):Java 8 新增,支持 Lambda 表达式。

推荐使用

  • 需要同时获取 key 和 value:用 entrySet
  • 只需要 key:用 keySet
  • 代码简洁且不关心性能:用 forEach

总结与建议

通过本文的 Java 实例 – 集合遍历 实战讲解,我们系统学习了五种主要遍历方式:

方式 适用场景 是否支持修改 优点 缺点
for-each 简单遍历 否(会抛异常) 代码简洁 不能安全删除
Iterator 需要删除元素 安全删除 语法稍复杂
传统 for 循环 索引操作 灵活控制 代码较长
Stream API 数据处理链 否(默认) 功能强大,可读性高 学习成本略高
Map 遍历 键值对处理 视方式而定 多样选择 选择需谨慎

实用建议

  • 初学者优先掌握 for-each 和 Iterator。
  • 中级开发者应熟悉 Stream API,提升代码质量。
  • 避免在遍历时直接修改集合,除非使用 Iterator.remove()。
  • Map 遍历时优先使用 entrySet,避免重复 get。

掌握这些技巧后,你将不再为“如何遍历集合”而烦恼。每一次遍历,都是一次对代码质量的提升。

记住,代码不仅仅是“能运行”,更要“好维护、易扩展”。而这一切,都始于对集合遍历的深刻理解。