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

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

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

1. Collection 体系(ListSet)的遍历方式

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

(1)增强 for 循环(foreach

语法

java 复制代码
for (元素类型 变量名 : 集合) {
    // 操作变量
}

适用场景

  • 仅需读取元素,无需修改集合结构(添加/删除元素)。
  • 所有 Collection 实现类(ListSet 均可)。

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

  • 无法获取元素索引(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<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        System.out.println("List遍历:");
        for (String s : list) {
            System.out.println(s);
        }

        // Set遍历
        Set<Integer> 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 实现类(ListSet 均可)。

优点

  • 支持遍历中安全删除元素(通过 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<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");

        Iterator<String> 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 无序无索引,不支持)。
  • 需要获取元素索引,或需要反向遍历(从后往前)。

优点

  • 可直接获取索引,方便定位元素。
  • 支持修改集合结构(如删除元素后调整索引)。

缺点 :仅适用于 ListSet 无法使用。

示例

java 复制代码
import java.util.ArrayList;
import java.util.List;

public class ForLoopDemo {
    public static void main(String[] args) {
        List<Integer> 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,双向遍历)

ListIteratorIterator 的子接口,仅 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<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");

        ListIterator<String> 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<? super T> action) 方法,可通过 Lambda 表达式遍历,代码更简洁。

语法

java 复制代码
集合.forEach(元素 -> {
    // 操作元素
});

适用场景

  • 仅需读取元素,无需修改集合结构。
  • 所有 Collection 实现类(ListSet 均可)。
  • 希望代码更简洁,适合函数式编程风格。

优点 :代码最简洁,一行搞定。
缺点:遍历中不能修改集合结构(否则抛异常),且无法直接获取索引。

示例

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<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        System.out.println("List遍历:");
        list.forEach(s -> System.out.println(s));

        // Set遍历
        Set<Integer> 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),遍历方式需围绕 keyvalue 或键值对(Entry)展开。

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

步骤

  1. keySet() 获取所有 keySet 集合。
  2. 遍历 key 集,通过 get(key) 获取对应 value

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

示例

java 复制代码
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapKeySetDemo {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("Java", 90);
        map.put("Python", 85);

        // 获取key集
        Set<String> keys = map.keySet();
        // 遍历key集
        for (String key : keys) {
            Integer value = map.get(key);
            System.out.println(key + " → " + value);
        }
    }
}
(2)遍历 value 集(仅需 value 时)

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

适用场景 :仅需要 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<String, Integer> map = new HashMap<>();
        map.put("Java", 90);
        map.put("Python", 85);

        // 获取value集
        Collection<Integer> values = map.values();
        // 遍历value集
        for (int score : values) {
            System.out.println("分数:" + score);
        }
    }
}
(3)遍历键值对(Entry 集,推荐)

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

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

示例

java 复制代码
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapEntrySetDemo {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("Java", 90);
        map.put("Python", 85);

        // 获取Entry集
        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        // 遍历Entry集
        for (Map.Entry<String, Integer> 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<? super K, ? super V> action) 方法,直接通过 Lambda 遍历键值对。

语法

java 复制代码
map.forEach((key, value) -> {
    // 操作key和value
});

适用场景 :需要简洁代码同时操作 keyvalue

示例

java 复制代码
import java.util.HashMap;
import java.util.Map;

public class MapForEachLambdaDemo {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("Java", 90);
        map.put("Python", 85);

        // Lambda遍历键值对
        map.forEach((key, value) -> {
            System.out.println(key + " → " + value);
        });
    }
}

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

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

1. 先确定集合类型:ListSet 还是 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无序 多线程环境下的键值对存储

三、集合使用的最佳实践

  1. 优先选择具体实现类 :声明集合时用接口(如 List<String> list = new ArrayList<>()),便于后续替换实现类。
  2. 初始化时指定容量 :如 new ArrayList<>(100),避免频繁扩容(哈希表默认容量16,负载因子0.75)。
  3. 遍历方式选择
    • 仅读取:用 forEach(Lambda)最简洁。
    • 需要删除元素:用 IteratorList 也可用普通for循环,但需注意索引调整)。
    • 需要索引:List 用普通for循环。
    • Map 优先用 entrySet() 遍历键值对(效率最高)。
  4. 避免集合嵌套过深 :如 Map<String, List<Map<String, Object>>> 会降低可读性,建议用实体类封装。
  5. 线程安全考量 :多线程场景下,ArrayList/HashMap 需替换为 CopyOnWriteArrayList/ConcurrentHashMap(而非 Collections.synchronizedList(),效率更高)。

总结

  • 遍历方式 :根据集合类型(List/Set/Map)和需求(是否修改、是否需要索引)选择,Iterator 适合删除元素,forEach(Lambda)适合简洁读取,entrySet()Map 最高效的遍历方式。
  • 集合选择 :根据"有序性""重复性""操作效率"决策------List 有序可重复,Set 无序去重,Map 键值对映射;具体实现类按查询/增删效率、排序需求选择。

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

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

相关推荐
Scott9999HH3 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔3 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社4 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海4 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖5 小时前
JDK 26 新特性详解
java·开发语言
马优晨5 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区7 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大8 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai8 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说8 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json