Java集合的遍历方式(全解析)

2026-02-27 10:51:38

一、集合的遍历方式(全解析)

Java 集合框架中,不同类型的集合(List、Set、Map)遍历方式略有差异,但核心目标是访问集合中的每个元素。以下按集合类型分类讲解所有遍历方式,包含语法、适用场景和注意事项。

1. Collection 体系(List、Set)的遍历方式

Collection 是单元素集合的根接口(List 和 Set 都继承它),通用遍历方式如下:

(1)增强 for 循环(foreach)

语法:

java

复制代码

for (元素类型 变量名 : 集合) {

// 操作变量

}

适用场景:

仅需读取元素,无需修改集合结构(添加/删除元素)。

所有 Collection 实现类(List、Set 均可)。

优点 :代码简洁,可读性高。

缺点:

无法获取元素索引(List 也不行)。

遍历中不能修改集合结构 (添加/删除元素),否则会抛出 ConcurrentModificationException。

示例:

java

复制代码

import java.util.ArrayList;

import java.util.HashSet;

import java.util.List;

import java.util.Set;

public class ForEachDemo {

public static void main(String[] args) {

// List遍历

List list = new ArrayList<>();

list.add("A");

list.add("B");

System.out.println("List遍历:");

for (String s : list) {

System.out.println(s);

}

// Set遍历

Set set = new HashSet<>();

set.add(1);

set.add(2);

System.out.println("Set遍历:");

for (int num : set) {

System.out.println(num);

}

}

}

(2)迭代器(Iterator)

语法:

java

复制代码

Iterator<元素类型> it = 集合.iterator();

while (it.hasNext()) { // 判断是否有下一个元素

元素类型 变量 = it.next(); // 获取下一个元素

// 操作变量

}

适用场景:

需要在遍历中删除元素(唯一安全的方式)。

所有 Collection 实现类(List、Set 均可)。

优点:

支持遍历中安全删除元素(通过 it.remove(),而非集合的 remove())。

可控制遍历过程(如提前终止)。

缺点:代码相对繁琐。

示例:

java

复制代码

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

public class IteratorDemo {

public static void main(String[] args) {

List list = new ArrayList<>();

list.add("A");

list.add("B");

list.add("C");

Iterator it = list.iterator();

while (it.hasNext()) {

String s = it.next();

if (s.equals("B")) {

it.remove(); // 安全删除当前元素(不会抛异常)

}

}

System.out.println("删除后集合:" + list); // [A, C]

}

}

注意:

调用 it.next() 前必须先调用 it.hasNext(),否则可能抛出 NoSuchElementException。

遍历中若通过集合的 remove() 方法删除元素(而非 it.remove()),会触发 ConcurrentModificationException。

(3)普通 for 循环(仅适用于 List)

语法:

java

复制代码

for (int i = 0; i < 集合.size(); i++) {

元素类型 变量 = 集合.get(i); // 通过索引获取元素

// 操作变量

}

适用场景:

仅 List 集合(因 List 有序且有索引,Set 无序无索引,不支持)。

需要获取元素索引,或需要反向遍历(从后往前)。

优点:

可直接获取索引,方便定位元素。

支持修改集合结构(如删除元素后调整索引)。

缺点 :仅适用于 List,Set 无法使用。

示例:

java

复制代码

import java.util.ArrayList;

import java.util.List;

public class ForLoopDemo {

public static void main(String[] args) {

List list = new ArrayList<>();

list.add(10);

list.add(20);

list.add(30);

// 正向遍历

System.out.println("正向遍历:");

for (int i = 0; i < list.size(); i++) {

System.out.println("索引" + i + ":" + list.get(i));

}

// 反向遍历

System.out.println("反向遍历:");

for (int i = list.size() - 1; i >= 0; i--) {

System.out.println("索引" + i + ":" + list.get(i));

}

}

}

(4)ListIterator(仅适用于 List,双向遍历)

ListIterator 是 Iterator 的子接口,仅 List 支持,可双向遍历 (向前/向后)和添加元素。

语法:

java

复制代码

ListIterator<元素类型> lit = 列表.listIterator();

// 向后遍历

while (lit.hasNext()) {

元素类型 变量 = lit.next();

}

// 向前遍历(需先向后遍历到末尾)

while (lit.hasPrevious()) {

元素类型 变量 = lit.previous();

}

适用场景:

List 集合需要双向遍历(如先向后再向前)。

需要在遍历中添加元素(lit.add(元素))。

示例:

java

复制代码

import java.util.ArrayList;

import java.util.List;

import java.util.ListIterator;

public class ListIteratorDemo {

public static void main(String[] args) {

List list = new ArrayList<>();

list.add("A");

list.add("B");

ListIterator lit = list.listIterator();

// 向后遍历并添加元素

while (lit.hasNext()) {

String s = lit.next();

if (s.equals("B")) {

lit.add("C"); // 在B之后添加C

}

}

System.out.println("添加后集合:" + list); // [A, B, C]

// 向前遍历

System.out.println("向前遍历:");

while (lit.hasPrevious()) {

System.out.println(lit.previous()); // C → B → A

}

}

}

(5)Java 8+ forEach 方法(结合 Lambda)

Collection 接口在 Java 8 中新增了 forEach(Consumer action) 方法,可通过 Lambda 表达式遍历,代码更简洁。

语法:

java

复制代码

集合.forEach(元素 -> {

// 操作元素

});

适用场景:

仅需读取元素,无需修改集合结构。

所有 Collection 实现类(List、Set 均可)。

希望代码更简洁,适合函数式编程风格。

优点 :代码最简洁,一行搞定。

缺点:遍历中不能修改集合结构(否则抛异常),且无法直接获取索引。

示例:

java

复制代码

import java.util.ArrayList;

import java.util.HashSet;

import java.util.List;

import java.util.Set;

public class ForEachLambdaDemo {

public static void main(String[] args) {

// List遍历

List list = new ArrayList<>();

list.add("Java");

list.add("Python");

System.out.println("List遍历:");

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

// Set遍历

Set set = new HashSet<>();

set.add(100);

set.add(200);

System.out.println("Set遍历:");

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

}

}

2. Map 体系的遍历方式

Map 存储键值对(key-value),遍历方式需围绕 key、value 或键值对(Entry)展开。

(1)遍历 key 集,再获取 value

步骤:

用 keySet() 获取所有 key 的 Set 集合。

遍历 key 集,通过 get(key) 获取对应 value。

适用场景 :需要同时使用 key 和 value,但 key 更易遍历。

示例:

java

复制代码

import java.util.HashMap;

import java.util.Map;

import java.util.Set;

public class MapKeySetDemo {

public static void main(String[] args) {

Map map = new HashMap<>();

map.put("Java", 90);

map.put("Python", 85);

// 获取key集

Set keys = map.keySet();

// 遍历key集

for (String key : keys) {

Integer value = map.get(key);

System.out.println(key + " → " + value);

}

}

}

(2)遍历 value 集(仅需 value 时)

步骤 :用 values() 获取所有 value 的 Collection 集合,直接遍历。

适用场景 :仅需要 value,无需 key。

示例:

java

复制代码

import java.util.Collection;

import java.util.HashMap;

import java.util.Map;

public class MapValuesDemo {

public static void main(String[] args) {

Map map = new HashMap<>();

map.put("Java", 90);

map.put("Python", 85);

// 获取value集

Collection values = map.values();

// 遍历value集

for (int score : values) {

System.out.println("分数:" + score);

}

}

}

(3)遍历键值对(Entry 集,推荐)

Map 中的每个键值对由 Map.Entry 对象表示,通过 entrySet() 获取所有 Entry 的 Set 集合,直接遍历键值对,效率最高(无需二次查询 value)。

适用场景 :需要同时操作 key 和 value(推荐优先使用)。

示例:

java

复制代码

import java.util.HashMap;

import java.util.Map;

import java.util.Set;

public class MapEntrySetDemo {

public static void main(String[] args) {

Map map = new HashMap<>();

map.put("Java", 90);

map.put("Python", 85);

// 获取Entry集

Set> entries = map.entrySet();

// 遍历Entry集

for (Map.Entry entry : entries) {

String key = entry.getKey();

Integer value = entry.getValue();

System.out.println(key + " → " + value);

}

}

}

(4)Java 8+ forEach 方法(结合 Lambda)

Map 接口在 Java 8 中新增 forEach(BiConsumer action) 方法,直接通过 Lambda 遍历键值对。

语法:

java

复制代码

map.forEach((key, value) -> {

// 操作key和value

});

适用场景 :需要简洁代码同时操作 key 和 value。

示例:

java

复制代码

import java.util.HashMap;

import java.util.Map;

public class MapForEachLambdaDemo {

public static void main(String[] args) {

Map map = new HashMap<>();

map.put("Java", 90);

map.put("Python", 85);

// Lambda遍历键值对

map.forEach((key, value) -> {

System.out.println(key + " → " + value);

});

}

}

二、集合的选择:什么时候用哪种集合?

集合的选择需根据业务需求(如是否有序、是否去重、操作效率等)决定,核心参考以下维度:

1. 先确定集合类型:List、Set 还是 Map?

List :需要有序、可重复的元素(如列表、数组扩展)。

Set :需要无序、不可重复的元素(如去重、唯一标识)。

Map :需要键值对映射(如字典、缓存、索引表)。

2. List 实现类的选择

实现类

底层结构

核心特点

适用场景

ArrayList

动态数组

查询快(O(1)),增删慢(中间位置 O(n))

频繁查询、少量增删(如用户列表、商品列表)

LinkedList

双向链表

增删快(首尾 O(1)),查询慢(O(n))

频繁增删(如队列、栈、链表结构)

3. Set 实现类的选择

实现类

底层结构

核心特点

适用场景

HashSet

哈希表

无序,去重,增删查效率高(O(1))

仅需去重,无需排序(如用户ID集合)

TreeSet

红黑树

有序(自然排序/自定义排序),去重

去重且需要排序(如排行榜、按规则排序的唯一元素)

4. Map 实现类的选择

实现类

底层结构

核心特点

适用场景

HashMap

哈希表

key无序,增删查效率高(O(1)),非线程安全

一般键值对存储(如缓存、配置映射)

TreeMap

红黑树

key有序(自然排序/自定义排序)

需要按key排序的键值对(如按日期排序的日志)

ConcurrentHashMap

哈希表(分段锁)

线程安全,高效并发,key无序

多线程环境下的键值对存储

三、集合使用的最佳实践

优先选择具体实现类 :声明集合时用接口(如 List list = new ArrayList<>()),便于后续替换实现类。

初始化时指定容量 :如 new ArrayList<>(100),避免频繁扩容(哈希表默认容量16,负载因子0.75)。

遍历方式选择 :

仅读取:用 forEach(Lambda)最简洁。

需要删除元素:用 Iterator(List 也可用普通for循环,但需注意索引调整)。

需要索引:List 用普通for循环。

Map 优先用 entrySet() 遍历键值对(效率最高)。

避免集合嵌套过深 :如 Map>> 会降低可读性,建议用实体类封装。

线程安全考量 :多线程场景下,ArrayList/HashMap 需替换为 CopyOnWriteArrayList/ConcurrentHashMap(而非 Collections.synchronizedList(),效率更高)。

总结

遍历方式 :根据集合类型(List/Set/Map)和需求(是否修改、是否需要索引)选择,Iterator 适合删除元素,forEach(Lambda)适合简洁读取,entrySet() 是 Map 最高效的遍历方式。

集合选择 :根据"有序性""重复性""操作效率"决策------List 有序可重复,Set 无序去重,Map 键值对映射;具体实现类按查询/增删效率、排序需求选择。

掌握这些规则,能写出高效、易维护的集合操作代码。

如需巩固本文内容,可点击以下链接完成相关练习:点击此处进入练习题。

比较:索尼linkbuds s和森海塞尔cx有啥区别?选择入手哪个好呢?
探索浦江镇的赛车天堂——锐擎卡丁车乐园