Skip to content

14.5 集合遍历

集合遍历的概念

集合遍历是指按照一定的顺序访问集合中的每个元素的过程。Java 集合框架提供了多种遍历集合的方法,每种方法都有其适用场景和优缺点。

1. Collection 集合的遍历

1.1 增强 for 循环

特点:语法简洁,适用于不需要修改集合的场景

示例

java
Collection<String> collection = new ArrayList<>();
collection.add("Java");
collection.add("Python");
collection.add("C++");

for (String element : collection) {
    System.out.println(element);
}

1.2 迭代器

特点:可以在遍历过程中修改集合(通过迭代器的 remove() 方法)

示例

java
Collection<String> collection = new ArrayList<>();
collection.add("Java");
collection.add("Python");
collection.add("C++");

Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    System.out.println(element);
    
    // 在遍历过程中删除元素
    if (element.equals("Python")) {
        iterator.remove();
    }
}

System.out.println("遍历后集合: " + collection); // [Java, C++]

1.3 forEach 方法(Java 8+)

特点:使用 lambda 表达式,代码简洁

示例

java
Collection<String> collection = new ArrayList<>();
collection.add("Java");
collection.add("Python");
collection.add("C++");

collection.forEach(element -> System.out.println(element));

// 或使用方法引用
collection.forEach(System.out::println);

2. List 集合的遍历

2.1 索引遍历

特点:可以通过索引直接访问元素,适用于需要索引的场景

示例

java
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");

for (int i = 0; i < list.size(); i++) {
    String element = list.get(i);
    System.out.println("索引 " + i + ": " + element);
}

2.2 增强 for 循环

特点:语法简洁,适用于不需要索引的场景

示例

java
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");

for (String element : list) {
    System.out.println(element);
}

2.3 迭代器

特点:可以在遍历过程中修改集合

示例

java
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    System.out.println(element);
}

2.4 ListIterator

特点:可以双向遍历,可以在遍历过程中修改集合(添加、删除、修改元素)

示例

java
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");

// 正向遍历
ListIterator<String> listIterator = list.listIterator();
while (listIterator.hasNext()) {
    String element = listIterator.next();
    System.out.println("正向: " + element);
    
    // 在遍历过程中添加元素
    if (element.equals("Python")) {
        listIterator.add("JavaScript");
    }
}

System.out.println("添加元素后: " + list); // [Java, Python, JavaScript, C++]

// 反向遍历
while (listIterator.hasPrevious()) {
    String element = listIterator.previous();
    System.out.println("反向: " + element);
}

2.5 forEach 方法(Java 8+)

特点:使用 lambda 表达式,代码简洁

示例

java
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");

list.forEach(element -> System.out.println(element));

3. Set 集合的遍历

3.1 增强 for 循环

特点:语法简洁

示例

java
Set<String> set = new HashSet<>();
set.add("Java");
set.add("Python");
set.add("C++");

for (String element : set) {
    System.out.println(element);
}

3.2 迭代器

特点:可以在遍历过程中修改集合

示例

java
Set<String> set = new HashSet<>();
set.add("Java");
set.add("Python");
set.add("C++");

Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    System.out.println(element);
    
    // 在遍历过程中删除元素
    if (element.equals("Python")) {
        iterator.remove();
    }
}

System.out.println("遍历后集合: " + set); // [Java, C++]

3.3 forEach 方法(Java 8+)

特点:使用 lambda 表达式,代码简洁

示例

java
Set<String> set = new HashSet<>();
set.add("Java");
set.add("Python");
set.add("C++");

set.forEach(element -> System.out.println(element));

4. Map 集合的遍历

4.1 遍历键

特点:只遍历键,适用于只需要键的场景

示例

java
Map<String, Integer> map = new HashMap<>();
map.put("Java", 95);
map.put("Python", 85);
map.put("C++", 90);

for (String key : map.keySet()) {
    System.out.println("Key: " + key);
}

4.2 遍历值

特点:只遍历值,适用于只需要值的场景

示例

java
Map<String, Integer> map = new HashMap<>();
map.put("Java", 95);
map.put("Python", 85);
map.put("C++", 90);

for (int value : map.values()) {
    System.out.println("Value: " + value);
}

4.3 遍历键值对

特点:同时遍历键和值,适用于需要两者的场景

示例

java
Map<String, Integer> map = new HashMap<>();
map.put("Java", 95);
map.put("Python", 85);
map.put("C++", 90);

for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}

4.4 迭代器遍历

特点:可以在遍历过程中修改 Map

示例

java
Map<String, Integer> map = new HashMap<>();
map.put("Java", 95);
map.put("Python", 85);
map.put("C++", 90);

// 遍历键值对
Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
    Map.Entry<String, Integer> entry = iterator.next();
    System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
    
    // 在遍历过程中删除元素
    if (entry.getKey().equals("Python")) {
        iterator.remove();
    }
}

System.out.println("遍历后 Map: " + map); // {Java=95, C++=90}

4.5 forEach 方法(Java 8+)

特点:使用 lambda 表达式,代码简洁

示例

java
Map<String, Integer> map = new HashMap<>();
map.put("Java", 95);
map.put("Python", 85);
map.put("C++", 90);

map.forEach((key, value) -> System.out.println("Key: " + key + ", Value: " + value));

5. 遍历性能比较

5.1 List 遍历性能

遍历方式适用场景性能
索引遍历需要索引的场景ArrayList 快,LinkedList 慢
增强 for 循环不需要索引的场景
迭代器需要在遍历过程中修改集合
forEach 方法代码简洁性优先

5.2 Set 遍历性能

遍历方式适用场景性能
增强 for 循环不需要修改集合
迭代器需要在遍历过程中修改集合
forEach 方法代码简洁性优先

5.3 Map 遍历性能

遍历方式适用场景性能
遍历键值对需要同时使用键和值
遍历键只需要键
遍历值只需要值
forEach 方法代码简洁性优先

6. 遍历中的常见问题

6.1 并发修改异常

症状:在增强 for 循环中修改集合,导致 ConcurrentModificationException

解决方案:使用迭代器的 remove() 方法,或使用 ListIterator 进行修改

示例

java
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");

// 错误:在增强 for 循环中修改集合
// for (String element : list) {
//     if (element.equals("Python")) {
//         list.remove(element);
//     }
// }

// 正确:使用迭代器
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    if (element.equals("Python")) {
        iterator.remove(); // 使用迭代器的 remove 方法
    }
}

// 正确:使用 ListIterator
ListIterator<String> listIterator = list.listIterator();
while (listIterator.hasNext()) {
    String element = listIterator.next();
    if (element.equals("Python")) {
        listIterator.remove();
        listIterator.add("JavaScript"); // 可以添加元素
    }
}

6.2 遍历顺序问题

症状:遍历顺序与预期不符

解决方案:选择合适的集合实现

示例

java
// HashSet 不保证遍历顺序
Set<String> hashSet = new HashSet<>();
hashSet.add("Java");
hashSet.add("Python");
hashSet.add("C++");
System.out.println("HashSet 遍历顺序: " + hashSet);

// LinkedHashSet 保证插入顺序
Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("Java");
linkedHashSet.add("Python");
linkedHashSet.add("C++");
System.out.println("LinkedHashSet 遍历顺序: " + linkedHashSet);

// TreeSet 保证自然顺序
Set<String> treeSet = new TreeSet<>();
treeSet.add("Java");
treeSet.add("Python");
treeSet.add("C++");
System.out.println("TreeSet 遍历顺序: " + treeSet);

6.3 遍历中的空指针异常

症状:遍历过程中遇到 NullPointerException

解决方案:在遍历前检查集合是否为 null,在遍历过程中检查元素是否为 null

示例

java
// 检查集合是否为 null
List<String> list = null;
if (list != null) {
    for (String element : list) {
        System.out.println(element);
    }
}

// 检查元素是否为 null
List<String> list2 = new ArrayList<>();
list2.add("Java");
list2.add(null);
list2.add("C++");

for (String element : list2) {
    if (element != null) {
        System.out.println(element.length());
    }
}

7. 示例:集合遍历的应用

7.1 学生成绩统计

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

class Student {
    private String name;
    private int score;
    
    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
    
    public String getName() {
        return name;
    }
    
    public int getScore() {
        return score;
    }
    
    @Override
    public String toString() {
        return "Student{name='" + name + "', score=" + score + "}";
    }
}

public class StudentScoreStatistics {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student("Alice", 95));
        students.add(new Student("Bob", 85));
        students.add(new Student("Charlie", 90));
        students.add(new Student("David", 80));
        students.add(new Student("Eve", 92));
        
        // 计算平均成绩
        int totalScore = 0;
        for (Student student : students) {
            totalScore += student.getScore();
        }
        double averageScore = (double) totalScore / students.size();
        System.out.println("平均成绩: " + averageScore);
        
        // 找出最高分
        int maxScore = Integer.MIN_VALUE;
        String topStudentName = "";
        for (Student student : students) {
            if (student.getScore() > maxScore) {
                maxScore = student.getScore();
                topStudentName = student.getName();
            }
        }
        System.out.println("最高分: " + maxScore + " (" + topStudentName + ")");
        
        // 找出不及格的学生
        System.out.println("不及格的学生:");
        for (Student student : students) {
            if (student.getScore() < 60) {
                System.out.println(student);
            }
        }
        
        // 使用 forEach 方法打印所有学生
        System.out.println("所有学生:");
        students.forEach(System.out::println);
    }
}

7.2 单词频率统计

java
import java.util.HashMap;
import java.util.Map;

public class WordFrequency {
    public static void main(String[] args) {
        String text = "Java is a programming language. Java is widely used. Java is popular.";
        
        // 分割文本为单词
        String[] words = text.toLowerCase().split("\\W+");
        
        // 统计单词频率
        Map<String, Integer> frequencyMap = new HashMap<>();
        for (String word : words) {
            if (!word.isEmpty()) {
                frequencyMap.put(word, frequencyMap.getOrDefault(word, 0) + 1);
            }
        }
        
        // 打印单词频率
        System.out.println("单词频率统计:");
        for (Map.Entry<String, Integer> entry : frequencyMap.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
        
        // 使用 forEach 方法打印
        System.out.println("\n使用 forEach 方法:");
        frequencyMap.forEach((key, value) -> System.out.println(key + ": " + value));
    }
}

7.3 集合转换

java
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class CollectionConversion {
    public static void main(String[] args) {
        // List 转 Set(去重)
        List<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        list.add("Java"); // 重复元素
        list.add("C++");
        
        System.out.println("原始 List: " + list);
        
        Set<String> set = new HashSet<>(list);
        System.out.println("转换为 Set: " + set); // 去重
        
        // Set 转 List
        List<String> newList = new ArrayList<>(set);
        System.out.println("转换为 List: " + newList);
    }
}

8. 最佳实践

  1. 选择合适的遍历方式:根据具体需求选择合适的遍历方式

  2. 避免并发修改:在遍历过程中,使用迭代器的方法进行修改

  3. 注意空指针异常:在遍历前检查集合是否为 null,在遍历过程中检查元素是否为 null

  4. 考虑性能:对于不同的集合类型,选择性能最优的遍历方式

  5. 代码简洁性:在不需要修改集合的场景下,使用增强 for 循环或 forEach 方法

  6. 利用 lambda 表达式:在 Java 8+ 中,使用 lambda 表达式和方法引用使代码更简洁

  7. 选择合适的集合实现:根据遍历顺序的需求,选择合适的集合实现

总结

Java 集合框架提供了多种遍历集合的方法,每种方法都有其适用场景:

  1. Collection 集合:增强 for 循环、迭代器、forEach 方法

  2. List 集合:索引遍历、增强 for 循环、迭代器、ListIterator、forEach 方法

  3. Set 集合:增强 for 循环、迭代器、forEach 方法

  4. Map 集合:遍历键、遍历值、遍历键值对、迭代器、forEach 方法

在遍历集合时,需要注意:

  • 避免在增强 for 循环中修改集合
  • 注意空指针异常
  • 根据具体需求选择合适的遍历方式
  • 考虑遍历的性能和顺序

通过合理选择和使用遍历方法,可以提高代码的效率和可维护性。

© 2026 编程马·菜鸟教程 版权所有