JDK 21 正式引入了一个全新的接口——SequencedMap,它为那些需要严格保持插入顺序、同时支持在序列首尾高效操作的有序 Map 场景,提供了统一的标准。该接口原生提供了getFirstEntry、putFirst、putLast、reversed等便捷方法。目前LinkedHashMap已经实现了这个接口,而像HashMap这种不保证顺序的 Map 如果调用这些方法,则会直接抛出异常。

注意,Java 的 Map 接口本身在 JDK 21 中并没有直接新增 putFirst、putLast 或 reversed 方法。这些能力实际上来自于新引入的 SequencedMap 接口——它是 JDK 21 中对有序 Map 的标准化抽象,继承自 Map,并明确建模了“可遍历顺序”和“可修改顺序”的语义。
SequencedMap 接口详解
该接口位于 java.util 包下,其核心是定义了一种保持插入顺序(或用户定义顺序)、并支持在序列首尾高效操作的 Map 行为。需要强调的是,SequencedMap 并非要替代 LinkedHashMap,而是为了给 LinkedHashMap 以及类似的有序实现(例如 TreeMap 在有序场景下)提供一个统一的契约。具体来说:
- 所有方法均基于“序列位置”而非仅仅基于键值对逻辑;
- 新增了默认方法,例如
getFirstEntry()、getLastEntry()、putFirst(K,V)、putLast(K,V); - 提供了
reversed()方法,返回一个实时、可变、反向视图——注意这不是副本,修改视图会同步反映到原 Map; LinkedHashMap以及第三方实现的ConcurrentLinkedHashMap等已经实现了该接口,JDK 自带的LinkedHashMap在 JDK 21+ 中直接实现了SequencedMap。
如何正确使用 putFirst 与 putLast
这两个方法仅对支持“序列首尾插入”的实现有效,例如 LinkedHashMap。具体用法如下:
map.putFirst("a", 1)会将键"a"插入到序列最前面,如果键已存在,则将其移动到首位并更新对应的值;map.putLast("b", 2)则是插入到序列最后,同样如果键已存在,会将其移动到末尾并更新值;- 如果 Map 不支持该操作(例如
HashMap),调用会抛出UnsupportedOperationException; - 需要注意的是,这和
put()方法不同:put()只是按哈希或比较逻辑插入,不会改变已有元素的相对顺序。
reversed() 视图的关键特性与使用技巧
SequencedMap.reversed() 返回的是一个反向、可变、延迟绑定的视图。其关键特性包括:
- 不是拷贝,因此内存开销极小;
- 对视图的
put、remove、putFirst等操作会直接作用于原 Map,只是语义上首尾互换; - 举个例子:
revMap = map.reversed(); revMap.putFirst("x", 99);实际上会把"x"插入到原 map 的末尾; - 视图与原 Map 始终保持强一致性,包括迭代顺序、大小、空状态等。
实际编码建议与注意事项
为了安全地使用这些新能力,这里提供几个实用建议:
- 声明类型时优先使用
SequencedMap而非Map,这样可以在编译时获得类型安全保障; - 创建实例仍然使用
new LinkedHashMap<>(),因为它已经实现了SequencedMap接口; - 切记不要对非
SequencedMap实现(例如HashMap)进行强制转型,否则运行时会导致失败; - 注意并发场景:标准的
LinkedHashMap仍然不是线程安全的,多线程环境下需要额外同步,或者选用并发友好的实现(例如ConcurrentLinkedHashMap)。
实际上,这些方法并不复杂,但有一个容易忽略的关键点:它们真正的价值不在于“新增功能”,而在于将长期被 LinkedHashMap 隐式支持、却缺乏统一 API 的行为,提升为标准契约。这样一来,顺序敏感的 Map 操作就变得更加清晰、更可组合、更易于推理了。
