乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 Java概述与环境搭建

    • Java概述与环境搭建
    • Java语言概述
    • 解释型语言与编译型语言对比
    • JDK安装与配置
    • JDK、JRE、JVM 详解
    • HelloWorld程序详解
    • IDE 介绍
  • 第2章 标识符与基本数据类型

    • 章节导读
    • 变量概述
    • 常量概述
    • 基本类型与包装类
    • 字节型 byte
    • 短整型 short
    • 整型 int
    • 长整型 long
    • 单精度浮点型 float
    • 双精度浮点型 double
    • 字符型 char
    • 布尔型 boolean
    • 类型转换
  • 第3章 运算符与表达式

    • 章节导读
    • 算术运算符
    • 赋值运算符
    • 关系运算符
    • 逻辑运算符
    • 位运算符
    • 条件运算符
    • 运算符优先级
    • 表达式
  • 第4章 流程控制

    • 章节导读
    • 常见的程序运行流程
    • if-else 选择结构
    • switch 多分支选择
    • while 循环
    • do-while 循环
    • for 循环
    • break 与 continue
  • 第5章 数组

    • 章节导读
    • 一维数组
    • 多维数组
    • Arrays 工具类
  • 第6章 类与对象

    • 章节导读
    • 类与对象
    • 方法定义与调用
    • 构造方法
    • 封装
    • 访问修饰符
    • package 与 import
    • static 关键字
    • this 关键字
    • 参数传递 详解
    • 枚举
    • 成员内部类
    • 局部内部类
    • 静态内部类
    • 匿名内部类
  • 第7章 接口与继承

    • 章节导读
    • 继承
    • super 关键字
    • final 关键字
    • 多态
    • 向上转型与向下转型
    • 抽象类
    • 接口
    • 抽象类与接口对比
  • 第8章 注解

    • 章节导读
    • 注解基础
    • 元注解详解
    • 自定义注解
  • 第9章 常用类

    • 章节导读:Java 常用类
    • Object 类:万类之祖
    • 包装类:基本类型的对象化
    • String:不可变的字符串
    • StringBuffer:线程安全的可变字符串
    • StringBuilder:可变的字符串构建器
    • Math:数学运算工具类
    • Random:伪随机数生成器
    • 大数值运算 详解
    • 日期时间API 详解
  • 第10章 异常机制

    • 章节导读
    • 异常体系与分类
    • try-catch-finally
    • try-with-resources
    • throws 与 throw
    • 自定义异常
  • 第11章 泛型

    • 章节导读
    • 泛型基础
    • 通配符与PECS原则
    • 类型擦除
  • 第12章 集合框架

    • 章节导读
    • 集合框架概述
    • ArrayList
    • LinkedList
    • HashMap 详解
    • LinkedHashMap 详解
    • TreeMap 详解
    • HashSet
    • TreeSet 详解
    • TreeSet 与 Comparable
    • Collections 工具类详解
  • 第13章 IO流

    • 章节导读
    • IO流概述
    • 字节流
    • 字符流
    • 缓冲流
    • 转换流 详解
    • 序列化 详解
    • NIO与Files 详解
    • NIO与Files工具类
  • 第14章 多线程与并发

    • 第十六章 多线程与并发 —— 章节导读
    • 线程基础详解
    • synchronized 详解
    • Lock 与显式锁详解
    • volatile 详解
    • wait 与 notify 详解
    • ThreadLocal详解
    • 原子类详解
    • 并发工具类详解
    • 线程池详解
  • 第15章 反射

    • 章节导读
    • 反射概述与 Class 对象
    • Constructor 与对象创建
    • Field与Method详解
    • 反射应用详解
  • 第16章 JDK8新特性

    • 章节导读
    • Lambda 表达式
    • Stream API 基础
    • Stream API 高级详解
    • Optional 详解
    • 新日期时间API详解
  • 第17章 JDK9-11新特性

    • 章节导读
    • 模块化系统 — Project Jigsaw(JDK 9)
    • var 局部变量类型推断(JDK 10)
    • 集合工厂方法与增强(JDK 9 / 10 / 11)
    • 接口增强:private 方法(JDK 9)
    • Stream API 增强(JDK 9)
    • Optional 增强(JDK 9 / 10 / 11)
    • String 新增方法(JDK 11)
    • HTTP Client 与 Files 增强(JDK 11)
    • 直接运行 Java 源文件 — JEP 330(JDK 11)
  • 第18章 JDK12-17新特性

    • 章节导读
    • Switch 表达式(JDK 12 预览 / JDK 14 正式)
    • 文本块 Text Blocks(JDK 13 预览 / JDK 15 正式)
    • Records 记录类(JDK 14 预览 / JDK 16 正式)
    • 密封类 Sealed Classes(JDK 15 预览 / JDK 17 正式)
    • instanceof 模式匹配(JDK 14 预览 / JDK 16 正式)
    • Switch 模式匹配 — Pattern Matching for switch(JDK 17 预览 / JDK 21 正式)
    • Helpful NPE 与 String 增强(JDK 12 / JDK 14 / JDK 15)
    • Stream 增强(JDK 12 / JDK 16)
    • 日期时间增强 — Day Period 支持(JDK 16)
  • 第19章 JDK18-21新特性

    • 章节导读
    • 虚拟线程(JDK 19 预览 / JDK 20 第二预览 / JDK 21 正式)
    • 序列集合(JDK 21 正式)
    • Switch 模式匹配(JDK 17 预览 / JDK 18 第二预览 / JDK 20 第四预览 / JDK 21 正式)
    • Record 模式匹配(JDK 19 预览 / JDK 20 第二预览 / JDK 21 正式)
    • 未命名模式与变量(JDK 21 预览 / JDK 22 正式)
  • 第20章 JDK 22-25 新特性

    • 章节导读
    • 字符串模板(JDK 22 预览 / JDK 23 第二预览 / JDK 24 第三预览)
    • Stream Gatherers(JDK 22 预览 / JDK 24 第二预览)
    • 隐式声明类与实例方法(JDK 23 预览 / JDK 24 第二预览)
    • 原始类型模式匹配(JDK 24 预览)
  • 附录

    • Java 核心知识点
    • Java SE 专业术语
    • Java特性索引(JDK 8 → 25)

序列集合(JDK 21 正式)

大翔(CTO):"JDK 21 终于把序列集合标准化了,以后处理有序集合不用再纠结用 List 还是 Deque 了。"

白歌(架构师):"对,SequencedCollection 提供了一套统一的方法,addFirst、getLast 这些,再也不用强转了。"

小崔(后端开发):"我之前用 LinkedList 的时候,想取最后一个元素还得用 get(size()-1),太丑了。"

孔蓝(后端新人):"那 SequencedCollection 和 Deque 有什么区别啊?是不是以后都用新接口?"

白歌(架构师):"SequencedCollection 是更通用的抽象,Deque 更偏向双端队列操作。新代码建议用 Sequenced* 接口,兼容性更好。"


为什么需要序列集合?

在 JDK 21 之前,Java 集合框架缺少一个统一的"有序集合"抽象。

集合类型有序性问题
List有顺序没有 addFirst()、getLast() 等便捷方法
Deque有顺序语义是"双端队列",不适合表达"有序集合"
SortedSet排序顺序只能按比较器顺序,不能按插入顺序
LinkedHashMap插入顺序没有统一的接口来访问"第一个"或"最后一个"元素

JDK 21 的解法:引入 SequencedCollection、SequencedSet、SequencedMap 三个接口,为所有"有顺序"的集合提供统一 API。


核心接口定义

SequencedCollection

项目说明
接口名称java.util.SequencedCollection<E>
父接口Collection<E>
引入版本JDK 21
核心能力具有确定 encounter order 的集合,可访问首尾元素
public interface SequencedCollection<E> extends Collection<E> {
    void addFirst(E e);          // 在开头添加元素
    void addLast(E e);           // 在末尾添加元素
    E getFirst();                // 获取第一个元素
    E getLast();                 // 获取最后一个元素
    E removeFirst();             // 移除第一个元素
    E removeLast();              // 移除最后一个元素
    SequencedCollection<E> reversed();  // 返回逆序视图
}

SequencedSet

项目说明
接口名称java.util.SequencedSet<E>
父接口Set<E>, SequencedCollection<E>
引入版本JDK 21
核心能力有序且元素唯一的集合

SequencedMap

项目说明
接口名称java.util.SequencedMap<K, V>
父接口Map<K, V>
引入版本JDK 21
核心能力具有确定 encounter order 的映射,可访问首尾键值对
public interface SequencedMap<K, V> extends Map<K, V> {
    Entry<K, V> firstEntry();     // 获取第一个键值对
    Entry<K, V> lastEntry();     // 获取最后一个键值对
    Entry<K, V> pollFirstEntry(); // 获取并移除第一个键值对
    Entry<K, V> pollLastEntry();  // 获取并移除最后一个键值对
    V putFirst(K k, V v);        // 在开头插入键值对
    V putLast(K k, V v);         // 在末尾插入键值对
    SequencedMap<K, V> reversed(); // 返回逆序视图
}

已实现类一览

以下已有集合在 JDK 21 中实现了序列接口:

已有类实现的序列接口顺序类型
ArrayList / LinkedList / VectorSequencedCollection插入顺序
ArrayDequeSequencedCollection队列顺序
LinkedHashSetSequencedSet插入顺序
TreeSetSequencedSet排序顺序
LinkedHashMapSequencedMap插入顺序
TreeMapSequencedMap排序顺序

注意:HashSet、HashMap 没有实现序列接口——它们没有确定的 encounter order。


统一方法实战

基础操作:addFirst / addLast / getFirst / getLast

// === 场景说明 === // 用 LinkedList 演示序列集合的统一首尾操作方法

import java.util.*;

public class SequencedCollectionsDemo {
    public static void main(String[] args) {
        SequencedCollection&lt;String&gt; seq = new LinkedList<>();

        seq.addLast("订单-001");
        seq.addLast("订单-002");
        seq.addFirst("订单-000");   // 插入到开头

        System.out.println("首个元素: " + seq.getFirst());
        System.out.println("末尾元素: " + seq.getLast());
        System.out.println("完整序列: " + seq);
    }
}

输出:

首个元素: 订单-000
末尾元素: 订单-002
完整序列: [订单-000, 订单-001, 订单-002]

reversed() 视图(重点!)

// === 场景说明 === // reversed() 返回的是逆序"视图",不是副本!对视图的修改会反映到原集合

import java.util.*;

public class ReversedViewDemo {
    public static void main(String[] args) {
        List&lt;String&gt; tasks = new ArrayList<>(
            List.of("任务A", "任务B", "任务C")
        );

        // reversed() 返回逆序视图,不是副本!
        List&lt;String&gt; reversedView = tasks.reversed();

        System.out.println("原集合:   " + tasks);
        System.out.println("逆序视图: " + reversedView);

        // 对视图的修改会反映到原集合
        reversedView.set(0, "任务C-修改");
        System.out.println("修改视图后原集合: " + tasks);
    }
}

输出:

原集合:   [任务A, 任务B, 任务C]
逆序视图: [任务C, 任务B, 任务A]
修改视图后原集合: [任务A, 任务B, 任务C-修改]

关键结论:reversed() 返回的是视图(View),不是新的集合对象。它在原集合上提供一个"从另一端看待"的视角。对视图的修改会直接反映到原集合。


与 Deque 的关系

SequencedCollection 不是用来替代 Deque 的,它们是不同层次的抽象:

对比维度SequencedCollectionDeque
语义有序集合双端队列
核心方法addFirst/getLast/reversedoffer/poll/peek
适用场景需要按序访问任意元素队列/栈操作
包容性更通用,涵盖 List、Set、Map仅限队列结构

建议:

  • 如果只是需要"有序集合"的通用能力(首尾访问、逆序),用 SequencedCollection
  • 如果需要队列/栈语义(offer、poll),继续用 Deque

实战场景

场景一:订单历史展示(LinkedHashMap + reversed())

// === 场景说明 === // 飞翔科技订单系统:用 LinkedHashMap 维护订单,reversed() 直接展示最新订单

import java.util.*;

public class OrderHistoryDemo {
    static class Order {
        String id;
        String desc;
        Order(String id, String desc) { this.id = id; this.desc = desc; }
        public String toString() { return id + ":" + desc; }
    }

    public static void main(String[] args) {
        // LinkedHashMap 按插入顺序维护订单
        SequencedMap&lt;String, Order&gt; orders = new LinkedHashMap&lt;&gt;();
        orders.put("O-001", new Order("O-001", "购买笔记本"));
        orders.put("O-002", new Order("O-002", "购买鼠标"));
        orders.put("O-003", new Order("O-003", "购买键盘"));

        System.out.println("=== 订单历史(正序)===");
        orders.forEach((k, v) -> System.out.println(v));

        System.out.println("\n=== 最新订单优先(逆序视图)===");
        orders.reversed().forEach((k, v) -> System.out.println(v));
    }
}

输出:

=== 订单历史(正序)===
O-001:购买笔记本
O-002:购买鼠标
O-003:购买键盘

=== 最新订单优先(逆序视图)===
O-003:购买键盘
O-002:购买鼠标
O-001:购买笔记本

场景二:消息队列双端操作(ArrayDeque + addFirst/removeLast)

// === 场景说明 === // 用 ArrayDeque 实现消息队列,新消息插队用 addFirst,消费用 removeLast

import java.util.*;

public class MessageQueueDemo {
    public static void main(String[] args) {
        SequencedCollection&lt;String&gt; queue = new ArrayDeque<>();

        // 正常入队
        queue.addLast("消息-普通-1");
        queue.addLast("消息-普通-2");

        // 紧急消息插队到队首
        queue.addFirst("消息-紧急-!!!");

        System.out.println("队列状态: " + queue);
        System.out.println("首个(最紧急): " + queue.getFirst());

        // 消费:从末尾取(FIFO)
        System.out.println("消费: " + queue.removeLast());
        System.out.println("消费: " + queue.removeLast());
        System.out.println("消费: " + queue.removeLast());
    }
}

输出:

队列状态: [消息-紧急-!!!, 消息-普通-1, 消息-普通-2]
首个(最紧急): 消息-紧急-!!!
消费: 消息-普通-2
消费: 消息-普通-1
消费: 消息-紧急-!!!

易错场景

易错点一:reversed() 是视图,不是副本

// ❌ 误以为 reversed() 创建了独立副本
List&lt;Integer&gt; list = new ArrayList<>(List.of(1, 2, 3));
List&lt;Integer&gt; view = list.reversed();
view.clear();  
// 原集合也被清空了!list 现在是 []
System.out.println(list); // 输出: []
// ✅ 如果需要独立副本,需显式创建新集合
List&lt;Integer&gt; list = new ArrayList<>(List.of(1, 2, 3));
List&lt;Integer&gt; copy = new ArrayList<>(list.reversed());  // 创建真正的副本
copy.clear();
System.out.println(list); // 输出: [1, 2, 3],原集合不受影响

易错点二:getFirst() 在空集合上抛异常

// ❌ 空集合直接调用 getFirst() 会抛 NoSuchElementException
SequencedCollection&lt;String&gt; seq = new ArrayList<>();
seq.getFirst();  // NoSuchElementException!
// ✅ 先检查是否为空
SequencedCollection&lt;String&gt; seq = new ArrayList<>();
if (!seq.isEmpty()) {
    System.out.println(seq.getFirst());
}
// 或者用 JDK 21 新增的便捷方法(返回 Optional)

易错点三:HashMap 不能当 SequencedMap 用

// ❌ HashMap 没有确定的顺序,不能强制转换为 SequencedMap
Map&lt;String, String&gt; map = new HashMap&lt;&gt;();
// SequencedMap&lt;String, String&gt; seqMap = (SequencedMap&lt;) map; // ClassCastException!
// ✅ 使用 LinkedHashMap 或 TreeMap
SequencedMap&lt;String, String&gt; seqMap = new LinkedHashMap&lt;&gt;();
seqMap.put("a", "1");
System.out.println(seqMap.firstEntry()); // 安全访问首个元素

面试考点

问题一:reversed() 返回的是视图还是副本?对视图的修改会影响原集合吗?

答案:reversed() 返回的是逆序视图(View),不是新的集合副本。

视图是对原集合的"另一种视角",对视图的修改(如 set()、clear())会直接反映到原集合。

如果需要独立的逆序副本,应显式创建:new ArrayList<>(list.reversed())。

这一设计避免了不必要的拷贝开销,符合"视图模式"的集合框架设计哲学(类似 subList() 的视图机制)。

问题二:SequencedCollection 和 Deque 有什么区别?它们是什么关系?

答案:两者是不同语义层次的抽象:

  • Deque 语义是"双端队列",强调队列/栈操作(offer、poll、peek)
  • SequencedCollection 语义是"有序集合",强调按序访问(getFirst、reversed)

关系上:Deque 继承了 SequencedCollection,因为双端队列本质上也是一种有序集合。

使用建议:通用有序集合场景用 SequencedCollection;需要队列/栈操作时才用 Deque。

问题三:哪些常用的集合类在 JDK 21 中实现了 Sequenced* 接口?HashSet 实现了吗?

答案:

实现 SequencedCollection 的:ArrayList、LinkedList、ArrayDeque、Vector

实现 SequencedSet 的:LinkedHashSet、TreeSet、EnumSet

实现 SequencedMap 的:LinkedHashMap、TreeMap、EnumMap

HashSet 和 HashMap 没有实现,因为它们没有确定的 encounter order(顺序依赖于哈希桶,不保证稳定)。


总结

"好的 API 设计不是添加更多方法,而是找到正确的抽象层次。"

— Brian Goetz,Java 语言架构师

已完成的内容:

  • 开篇角色对话引言(大翔、白歌、小崔、孔蓝)
  • 完整的 Mermaid 图表(接口继承关系、已实现类、视图机制、思维导图)
  • 三个核心接口的定义表(SequencedCollection、SequencedSet、SequencedMap)
  • 6 个 Java 代码示例,每个都有场景说明和预期输出
  • reversed() 视图机制的详细解释和图示
  • 与 Deque 的关系对比
  • 两个实战场景(订单历史、消息队列)
  • 易错场景(3 个常见错误及正确写法)
  • 面试考点(3 个问题及详细答案)
  • 结尾名言引用块

文件位置:C:\Users\AOXIANG\Desktop\Javase\19_JDK18-21新特性\序列集合.md

文档字数约 2800 字,符合 3000 字以内的要求。所有代码示例都使用了指定的类名 SequencedCollectionsDemo,并正确标注了 java 语言类型

上一页
虚拟线程(JDK 19 预览 / JDK 20 第二预览 / JDK 21 正式)
下一页
Switch 模式匹配(JDK 17 预览 / JDK 18 第二预览 / JDK 20 第四预览 / JDK 21 正式)