🚀 Java 巩固进阶 · 第7天

主题:集合体系与 Collection 接口

📅 进度概览:正式进入「集合框架」核心篇。
💡 核心价值:这是Java开发中使用频率最高的基础设施。

  • 后端接口:Controller 返回的 List<User>
  • 参数封装:接收前端传来的 Map<String, Object>
  • ORM映射:MyBatis 查询结果自动映射为 ArrayList
  • 业务逻辑:去重统计、排序筛选、缓存临时数据。

今天我们将彻底吃透集合的宏观体系Collection 根接口,建立全局认知,为后续深入源码打下坚实基础。


一、为什么需要集合?(降维打击数组)

在 SpringBoot 项目中,我们几乎不再直接使用原生数组,原因如下:

维度 数组 (Array) ❌ 集合 (Collection) ✅ 实战痛点
长度 固定,初始化后不可变 动态扩容,按需增长 无法预知数据库查出一条还是万条数据
类型 只能存同一种类型 支持泛型 (<T>),类型安全 避免运行时 ClassCastException
功能 仅提供 length 和索引访问 内置 add, remove, contains 等丰富API 手动实现增删改查效率低且易错
场景 单一 多态适配 (List有序/Set去重/Map键值) 灵活应对复杂业务逻辑

二、Java 集合框架全景图

理解体系结构是掌握集合的关键。请牢记以下继承关系:

双列集合

Map
根接口

HashMap
最常用

LinkedHashMap

TreeMap

Hashtable
线程安全/老旧

单列集合

Collection
根接口

List
有序、可重复

Set
无序、唯一

Queue
队列

ArrayList
最常用/查询快

LinkedList
增删快

Vector
线程安全/老旧

HashSet
最常用

LinkedHashSet
保留插入顺序

TreeSet
自然排序

🔑 核心分类记忆法(先记这3个)

  1. List (列表)有序、可重复
    • 场景:商品列表、用户订单序列 [A, B, B, C]
  2. Set (集)无序(逻辑上)、不可重复
    • 场景:黑名单去重、标签集合 {A, B, C}
  3. Map (映射)键值对 (Key-Value),Key 唯一,Value 可重复。
    • 场景:配置项、缓存字典 {id: 1001, name: "张三"}

⚠️ 注意Map 不继承 Collection 接口,它是独立的顶层接口,但通常与集合框架统称为“Java Collections Framework”。


三、Collection 接口详解(List/Set 的父接口)

Collection 是所有单列集合的根接口。它定义了所有单列集合的“通用行为”,体现了多态的思想。

1. 核心方法速查表(必须熟记)

方法签名 作用描述 典型应用场景
boolean add(E e) 添加元素 将查询结果加入列表
boolean remove(Object o) 删除指定元素 移除无效数据
boolean contains(Object o) 判断是否存在 权限校验、黑名单检查
int size() 获取元素个数 分页计算总数
boolean isEmpty() 判空 避免空指针异常的最佳实践
void clear() 清空集合 重置临时缓存
Iterator<E> iterator() 获取迭代器 遍历集合的标准方式
Object[] toArray() 转为数组 兼容旧版API或特定算法

2. 代码实战:多态的魅力

在 SpringBoot 中,我们永远倾向于**“接口引用指向实现类”**,这样便于后期切换实现(如从 ArrayList 切换到 LinkedList)而不影响业务代码。

import java.util.ArrayList;
import java.util.Collection;

public class CollectionDemo {
    public static void main(String[] args) {
        // 【最佳实践】接口引用 (Collection) -> 实现类对象 (ArrayList)
        // 如果未来需要线程安全,只需改为 new Vector() 或 Collections.synchronizedList,无需修改下方逻辑
        Collection<String> users = new ArrayList<>();

        // 1. 增
        users.add("张三");
        users.add("李四");
        users.add("王五");
        System.out.println("📦 初始集合: " + users); 

        // 2. 删
        boolean isRemoved = users.remove("李四");
        System.out.println("🗑️ 删除李四成功? " + isRemoved + ", 当前: " + users);

        // 3. 查 (包含)
        if (users.contains("张三")) {
            System.out.println("✅ 张三在列表中");
        }

        // 4. 统计
        System.out.println("📊 当前人数: " + users.size());

        // 5. 清空
        users.clear();
        System.out.println("🧹 清空后是否为空: " + users.isEmpty());
    }
}

四、迭代器 (Iterator):集合遍历的“万能钥匙”

1. 为什么要用迭代器?

虽然可以用普通 for 循环通过索引遍历 List,但 Set 没有索引,且所有集合都需要一种统一的遍历方式。Iterator 就是这把万能钥匙。

2. 标准用法(含安全删除)

import java.util.*;

public class IteratorDemo {
    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<>(Arrays.asList("张三", "李四", "王五"));
        
        // 1. 获取迭代器
        Iterator<String> it = coll.iterator();

        // 2. 循环遍历
        while (it.hasNext()) {
            String name = it.next(); // 移动指针并获取元素
            System.out.println("正在处理: " + name);

            // ⚠️【关键】在遍历过程中删除元素,必须使用 it.remove()
            if ("李四".equals(name)) {
                it.remove(); 
                System.out.println("-> 已安全移除李四");
            }
        }
        System.out.println("最终结果: " + coll); // [张三, 王五]
    }
}

3. ⚠️ 避坑指南:并发修改异常 (ConcurrentModificationException)

这是新手最容易遇到的报错!

  • 错误写法:在 foreachiterator 遍历中,直接调用 coll.remove()
    • 后果:抛出 ConcurrentModificationException
    • 原理:迭代器内部维护了一个 expectedModCount,当集合结构被外部直接修改时,两者不一致,迭代器立即报错以保护数据安全(快速失败机制)。
  • 正确写法
    • 若需删除:必须使用 iterator.remove()
    • 若仅读取:推荐使用 增强 for 循环(语法糖),代码更简洁。
// ✅ 推荐:仅遍历读取时使用增强 for (底层仍是 Iterator)
for (String name : coll) {
    System.out.println(name); 
}
// ❌ 禁止:在增强 for 中调用 coll.remove(name),必崩!

五、🎯 今日实战任务:奇偶数大清洗

任务目标:深入理解迭代器的删除机制与异常原理。

📝 需求步骤

  1. 初始化:创建一个 Collection<Integer> (使用 ArrayList),存入 1 到 10 的整数。
  2. 安全删除:使用 Iterator 遍历集合,将所有偶数移除。
  3. 验证结果:打印剩余元素,预期输出应为 [1, 3, 5, 7, 9](顺序可能因实现类略有不同,但内容应一致)。
  4. 挑战实验(选做):
    • 尝试改用 增强 for 循环 (for (Integer i : list)) 并在循环内执行 list.remove(i)
    • 观察:程序是否崩溃?控制台报什么错?
    • 思考:为什么迭代器的 remove() 不会报错,而集合的 remove() 会报错?

💡 提示代码骨架

Collection<Integer> numbers = new ArrayList<>();
// ... 添加 1-10 ...

Iterator<Integer> it = numbers.iterator();
while(it.hasNext()){
    Integer num = it.next();
    if(num % 2 == 0){
        // 在这里填写删除代码
    }
}

📝 第8天 · 核心总结

  1. 体系认知:Java 集合分为 Collection (单列)Map (双列)。Collection 下分 List (有序可重) 和 Set (无序唯一)。
  2. 多态编程:SpringBoot 开发中,始终遵循 Collection<T> list = new ArrayList<>() 的写法,提高代码扩展性。
  3. 遍历铁律
    • 只读:首选增强 for 循环。
    • 删除:必须使用 Iteratorremove() 方法。
    • 禁忌:严禁在遍历过程中直接调用集合自身的 remove 方法,否则触发 快速失败机制 (Fail-Fast)

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐