Java 集合遍历

·
2026-02-27 10:51:48

Java 集合遍历

引言​

在Java编程中,集合是用来存储和操作一组数据的容器。而集合遍历则是我们日常编程中最常见的操作之一,它允许我们按特定顺序访问集合中的每个元素。掌握各种遍历方式对于有效处理集合数据至关重要。

本文将介绍Java集合框架中的多种遍历方法,从传统的迭代器到现代的Stream API,帮助你选择最适合特定场景的遍历技术。

集合遍历的基本方式​

1. 使用迭代器(Iterator)​

迭代器是Java集合框架的核心部分,提供了一种统一的方式来遍历集合。

import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class IteratorExample { public static void main(String[] args) { List fruits = new ArrayList<>(); fruits.add("苹果"); fruits.add("香蕉"); fruits.add("橙子"); Iterator iterator = fruits.iterator(); while (iterator.hasNext()) { String fruit = iterator.next(); System.out.println(fruit); } }}

输出:

苹果香蕉橙子

提示Iterator接口还提供remove()方法,可以在遍历过程中安全地删除元素。

2. 使用for-each循环​

Java 5引入的for-each循环(增强型for循环)提供了一种更简洁的遍历集合的方式:

import java.util.ArrayList;import java.util.List;public class ForEachExample { public static void main(String[] args) { List fruits = new ArrayList<>(); fruits.add("苹果"); fruits.add("香蕉"); fruits.add("橙子"); for (String fruit : fruits) { System.out.println(fruit); } }}

输出:

苹果香蕉橙子

3. 使用传统for循环(仅适用于List)​

当我们需要索引值时,可以使用传统for循环遍历List集合:

import java.util.ArrayList;import java.util.List;public class ForLoopExample { public static void main(String[] args) { List fruits = new ArrayList<>(); fruits.add("苹果"); fruits.add("香蕉"); fruits.add("橙子"); for (int i = 0; i < fruits.size(); i++) { System.out.println("索引 " + i + ": " + fruits.get(i)); } }}

输出:

索引 0: 苹果索引 1: 香蕉索引 2: 橙子

现代Java集合遍历方式​

1. 使用forEach方法与Lambda表达式(Java 8+)​

Java 8引入了函数式接口和Lambda表达式,使集合遍历更加简洁:

import java.util.ArrayList;import java.util.List;public class ForEachMethodExample { public static void main(String[] args) { List fruits = new ArrayList<>(); fruits.add("苹果"); fruits.add("香蕉"); fruits.add("橙子"); // 使用Lambda表达式 fruits.forEach(fruit -> System.out.println(fruit)); // 更简洁的方法引用 System.out.println("\n使用方法引用:"); fruits.forEach(System.out::println); }}

输出:

苹果香蕉橙子使用方法引用:苹果香蕉橙子

2. 使用Stream API(Java 8+)​

Stream API提供了强大的数据处理能力,特别适合复杂的集合操作:

import java.util.ArrayList;import java.util.List;public class StreamExample { public static void main(String[] args) { List fruits = new ArrayList<>(); fruits.add("苹果"); fruits.add("香蕉"); fruits.add("橙子"); fruits.add("葡萄"); // 筛选并输出长度大于2的水果名 System.out.println("长度大于2的水果:"); fruits.stream() .filter(fruit -> fruit.length() > 2) .forEach(System.out::println); }}

输出:

长度大于2的水果:香蕉橙子葡萄

不同集合类型的遍历​

1. 遍历List​

前面我们已经展示了遍历List的多种方式。这里不再重复。

2. 遍历Set​

Set集合不保证元素顺序,且不能通过索引访问:

import java.util.HashSet;import java.util.Set;public class SetTraversalExample { public static void main(String[] args) { Set numbers = new HashSet<>(); numbers.add(10); numbers.add(20); numbers.add(30); numbers.add(10); // 重复元素不会被添加 System.out.println("使用for-each遍历Set:"); for (Integer number : numbers) { System.out.println(number); } System.out.println("\n使用Iterator遍历Set:"); java.util.Iterator iterator = numbers.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } System.out.println("\n使用forEach方法遍历Set:"); numbers.forEach(System.out::println); }}

输出可能如下(Set不保证顺序):

使用for-each遍历Set:201030使用Iterator遍历Set:201030使用forEach方法遍历Set:201030

3. 遍历Map​

Map是键值对集合,有多种遍历方式:

import java.util.HashMap;import java.util.Map;public class MapTraversalExample { public static void main(String[] args) { Map fruitPrices = new HashMap<>(); fruitPrices.put("苹果", 5); fruitPrices.put("香蕉", 3); fruitPrices.put("橙子", 4); // 1. 遍历键值对 System.out.println("遍历键值对:"); for (Map.Entry entry : fruitPrices.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue() + "元"); } // 2. 仅遍历键 System.out.println("\n遍历键:"); for (String key : fruitPrices.keySet()) { System.out.println(key); } // 3. 仅遍历值 System.out.println("\n遍历值:"); for (Integer value : fruitPrices.values()) { System.out.println(value + "元"); } // 4. 使用forEach和Lambda System.out.println("\n使用forEach和Lambda:"); fruitPrices.forEach((fruit, price) -> System.out.println(fruit + ": " + price + "元")); }}

输出:

遍历键值对:苹果: 5元香蕉: 3元橙子: 4元遍历键:苹果香蕉橙子遍历值:5元3元4元使用forEach和Lambda:苹果: 5元香蕉: 3元橙子: 4元

各种遍历方式的性能比较​

不同的遍历方式在性能上有所差异:

警告在一般应用中,各遍历方式的性能差异很小。应根据代码可读性和实际需求选择合适的遍历方式。

实际应用案例​

案例1:购物车商品统计​

import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;class Product { private String name; private double price; private int quantity; public Product(String name, double price, int quantity) { this.name = name; this.price = price; this.quantity = quantity; } public String getName() { return name; } public double getPrice() { return price; } public int getQuantity() { return quantity; }}public class ShoppingCartExample { public static void main(String[] args) { // 创建购物车 List cart = new ArrayList<>(); cart.add(new Product("笔记本电脑", 5999, 1)); cart.add(new Product("鼠标", 99, 2)); cart.add(new Product("键盘", 199, 1)); cart.add(new Product("显示器", 1299, 1)); // 遍历计算总金额 double totalAmount = 0; System.out.println("购物车商品列表:"); System.out.println("--------------------------------"); System.out.printf("%-15s%-10s%-8s%-10s\n", "商品名称", "单价", "数量", "小计"); for (Product product : cart) { double itemTotal = product.getPrice() * product.getQuantity(); totalAmount += itemTotal; System.out.printf("%-15s%-10.2f%-8d%-10.2f\n", product.getName(), product.getPrice(), product.getQuantity(), itemTotal); } System.out.println("--------------------------------"); System.out.printf("总计: %.2f元\n", totalAmount); // 使用Stream API计算 double streamTotal = cart.stream() .mapToDouble(p -> p.getPrice() * p.getQuantity()) .sum(); System.out.printf("使用Stream API计算总计: %.2f元\n", streamTotal); }}

输出:

购物车商品列表:--------------------------------商品名称 单价 数量 小计 笔记本电脑 5999.00 1 5999.00 鼠标 99.00 2 198.00 键盘 199.00 1 199.00 显示器 1299.00 1 1299.00 --------------------------------总计: 7695.00元使用Stream API计算总计: 7695.00元

案例2:学生成绩统计分析​

import java.util.*;import java.util.stream.Collectors;class Student { private String name; private Map scores; // 课程-分数 public Student(String name) { this.name = name; this.scores = new HashMap<>(); } public void addScore(String course, int score) { scores.put(course, score); } public String getName() { return name; } public Map getScores() { return scores; } public double getAverageScore() { if (scores.isEmpty()) return 0; int sum = 0; for (int score : scores.values()) { sum += score; } return (double) sum / scores.size(); }}public class StudentScoreAnalysisExample { public static void main(String[] args) { // 创建学生数据 List students = new ArrayList<>(); Student s1 = new Student("张三"); s1.addScore("数学", 90); s1.addScore("语文", 85); s1.addScore("英语", 78); Student s2 = new Student("李四"); s2.addScore("数学", 75); s2.addScore("语文", 92); s2.addScore("英语", 83); Student s3 = new Student("王五"); s3.addScore("数学", 88); s3.addScore("语文", 79); s3.addScore("英语", 95); students.add(s1); students.add(s2); students.add(s3); // 传统方式计算平均分 System.out.println("学生平均分统计(传统方式):"); for (Student student : students) { System.out.printf("%-5s: %.2f\n", student.getName(), student.getAverageScore()); } // 使用Stream API找出数学成绩最高的学生 Optional topMathStudent = students.stream() .max(Comparator.comparingInt(s -> s.getScores().getOrDefault("数学", 0))); topMathStudent.ifPresent(student -> System.out.println("\n数学成绩最高的学生: " + student.getName() + ", 分数: " + student.getScores().get("数学"))); // 按平均分排序 System.out.println("\n按平均分排序后的学生名单:"); students.stream() .sorted(Comparator.comparingDouble(Student::getAverageScore).reversed()) .forEach(s -> System.out.printf("%-5s: %.2f\n", s.getName(), s.getAverageScore())); }}

输出:

学生平均分统计(传统方式):张三 : 84.33李四 : 83.33王五 : 87.33数学成绩最高的学生: 张三, 分数: 90按平均分排序后的学生名单:王五 : 87.33张三 : 84.33李四 : 83.33

遍历过程中修改集合的注意事项​

在遍历集合时修改集合内容需要特别小心:

注意使用for-each循环或迭代器遍历集合时,除了通过迭代器的remove()方法外,不应修改集合结构,否则会抛出ConcurrentModificationException。

安全删除元素的方法:

import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class SafeRemovalExample { public static void main(String[] args) { List fruits = new ArrayList<>(); fruits.add("苹果"); fruits.add("香蕉"); fruits.add("橙子"); fruits.add("西瓜"); System.out.println("原始列表: " + fruits); // 错误方式:在for-each循环中直接删除 /* for (String fruit : fruits) { if (fruit.equals("香蕉")) { fruits.remove(fruit); // 会抛出ConcurrentModificationException } } */ // 正确方式1:使用Iterator的remove方法 System.out.println("\n使用Iterator删除元素:"); Iterator iterator = fruits.iterator(); while (iterator.hasNext()) { String fruit = iterator.next(); if (fruit.equals("香蕉")) { iterator.remove(); // 安全删除当前元素 } } System.out.println("删除后: " + fruits); // 重置列表 fruits.clear(); fruits.add("苹果"); fruits.add("香蕉"); fruits.add("橙子"); fruits.add("西瓜"); // 正确方式2:使用removeIf方法(Java 8+) System.out.println("\n使用removeIf删除元素:"); fruits.removeIf(fruit -> fruit.equals("橙子")); System.out.println("删除后: " + fruits); }}

输出:

原始列表: [苹果, 香蕉, 橙子, 西瓜]使用Iterator删除元素:删除后: [苹果, 橙子, 西瓜]使用removeIf删除元素:删除后: [苹果, 香蕉, 西瓜]

总结​

本文详细介绍了Java集合遍历的多种方式,从传统的迭代器到现代的Stream API。选择合适的遍历方式取决于具体需求:

迭代器(Iterator): 灵活性高,可以在遍历时安全删除元素

For-Each循环: 语法简洁,适合大多数情况

传统For循环: 可以获取索引位置,但仅适用于List

Lambda表达式与forEach方法: 代码更简洁优雅

Stream API: 适合复杂数据处理和链式操作

不同的集合类型(List、Set、Map)有各自特定的遍历方式。在实际开发中,应根据代码可读性、业务需求和性能考虑选择最合适的遍历方法。

练习题​

编写程序,使用三种不同方式遍历ArrayList,并比较它们的代码简洁性。

创建一个HashMap存储学生姓名和成绩,然后使用不同方式遍历输出。

使用Stream API筛选出列表中的偶数并计算它们的和。

编写程序,安全地从ArrayList中删除满足特定条件的元素。

参考资源​

Java官方文档: Collections Framework Overview

Stream API: java.util.stream

Java Lambda表达式: Lambda Expressions