1. 概述
Java 21 预计于2023年9月发布,作为继Java 17之后的下一个长期支持版本。在新特性中,Java的集合框架迎来了一项重要更新——**有序集合 (Sequenced Collections)**。
这项新特性堪称颠覆性改进,它将彻底改变开发者与集合的交互方式。通过向现有继承体系中注入新接口,提供了直接访问集合首尾元素的内置方法,同时支持获取集合的反向视图。
本文将深入探讨这一新特性、潜在风险及其带来的优势。
2. 动机
缺乏具有明确定义顺序的通用集合超类型,一直是Java开发中的痛点。特别是缺少统一的首尾元素访问方法和反向迭代支持,已成为Java集合框架的长期短板。
以List和Deque为例:两者都定义了元素顺序,但它们的共同超类型Collection却没有。同样,Set本身不定义顺序,但某些子类型如SortedSet和LinkedHashSet却具备顺序特性。这种顺序支持分散在类型体系中,导致相关操作要么不一致,要么直接缺失。
为说明这种不一致性,我们对比不同集合类型的首尾元素访问方式:
集合类型 | 获取首元素 | 获取尾元素 |
---|---|---|
List | list.get(0) |
list.get(list.size() - 1) |
Deque | deque.getFirst() |
deque.getLast() |
SortedSet | sortedSet.first() |
sortedSet.last() |
LinkedHashSet | linkedHashSet.iterator().next() |
// 缺失方法 |
获取集合反向视图时同样存在混乱。虽然从首到尾的迭代模式清晰一致,但反向操作却充满挑战:
- NavigableSet 使用
descendingSet()
- Deque 使用
descendingIterator()
- List 使用
listIterator()
- LinkedHashSet 则完全不支持反向迭代
这些差异导致代码库碎片化,增加了复杂度,使得在API中表达某些通用概念变得异常困难。
3. 新的Java集合继承体系
该特性引入了三个新接口:有序集合(Sequenced Collection)、有序集(Sequenced Set)和有序映射(Sequenced Map),它们被整合到现有集合继承体系中:
图片来源:JEP 431: Sequenced Collections 官方文档
3.1. SequencedCollection
有序集合是具有明确定义元素顺序的Collection。 新的SequencedCollection接口提供了在集合两端添加、获取或删除元素的方法,以及获取集合反向视图的方法:
interface SequencedCollection<E> extends Collection<E> {
// 新增方法
SequencedCollection<E> reversed();
// 从Deque提升的方法
void addFirst(E);
void addLast(E);
E getFirst();
E getLast();
E removeFirst();
E removeLast();
}
✅ 除reversed()
外,所有方法都是默认方法,实现从Deque提升而来
✅ reversed()
提供原始集合的反向视图,对原集合的修改会同步反映在反向视图中
⚠️ add*()
和remove*()
方法在不可修改集合或已定义排序的集合中会抛出UnsupportedOperationException
⚠️ 当集合为空时,get*()
和remove*()
方法会抛出NoSuchElementException
3.2. SequencedSet
有序集是特殊的Set,它同时作为SequencedCollection工作,并确保元素唯一性。 SequencedSet接口继承SequencedCollection并重写其reversed()
方法,唯一区别是返回类型变为SequencedSet:
interface SequencedSet<E> extends Set<E>, SequencedCollection<E> {
// 协变重写
SequencedSet<E> reversed();
}
3.3. SequencedMap
有序映射是具有明确定义条目顺序的Map。 SequencedMap不继承SequencedCollection,而是提供自己的方法来操作集合两端的元素:
interface SequencedMap<K, V> extends Map<K, V> {
// 新增方法
SequencedMap<K, V> reversed();
SequencedSet<K> sequencedKeySet();
SequencedCollection<V> sequencedValues();
SequencedSet<Entry<K, V>> sequencedEntrySet();
V putFirst(K, V);
V putLast(K, V);
// 从NavigableMap提升的方法
Entry<K, V> firstEntry();
Entry<K, V> lastEntry();
Entry<K, V> pollFirstEntry();
Entry<K, V> pollLastEntry();
}
✅ put*()
方法在不可修改映射或已定义排序的映射中会抛出UnsupportedOperationException
⚠️ 在空映射上调用从NavigableMap提升的方法会抛出NoSuchElementException
4. 潜在风险
新接口的引入本不应影响仅使用集合实现的代码,但如果代码库中定义了自定义集合类型,可能会出现以下冲突:
- 方法命名冲突:新增方法可能与现有类中的方法冲突。例如,如果自定义的List实现已定义
getFirst()
方法但返回类型与SequencedCollection中的不同,升级到Java 21时会导致源码不兼容 - 协变重写冲突:List和Deque都对
reversed()
方法进行了协变重写(分别返回List和Deque)。任何同时实现这两个接口的自定义集合在升级时会导致编译错误,因为编译器无法确定选择哪个重写版本
完整风险分析可参考JDK-8266572报告。
5. 总结
有序集合 (Sequenced Collections) 标志着Java集合框架的重大进步。通过解决长期存在的统一处理有序集合的需求,Java使开发者能够更高效、更直观地工作。新接口建立了更清晰的结构和一致的行为,从而产生更健壮、更易读的代码。
本文源码可在GitHub获取。