Dealing with Collections is improving with Java 21, as three new interfaces get retro-fitted right into the existing type hierarchies. These Sequenced Collections give us a uniform API to access the first and last elements, and process Collections in reverse.
To better understand what Sequenced Collections are, let’s take a look a what Collections were before.
The Java Collections Framework
Introduced in Java 1.2, the Collections Framework gave use many interfaces and classes to represent groups of objects. This unified API has many advantages, like enabling interoperability between unrelated APIs with “standardized” Collection types, and therefore, fostering code reuse.
Over a dozen interfaces provide an excellent abstraction for the underlying general- and special-purpose implementations, including implementation for concurrent environments. Even though the type hierarchies and functionality of the different Collection types is well-thought-out and give a lot of flexibility and functionality, a certain aspect is missing… until now!
Front to Back, Back to Front
A quite common task with Collections is getting the first or last element, and usually, it’s not pretty… I’m pretty sure everyone reading this article has done the following countless times:
Some Collection types support accessing the first and last element directly, but there’s no shared interface with a common API (yet):
|Collection Type||First Element||Last Element|
The first element is also accessible through the
Iterator<E>, too, but it feels like a cheat:
Collection-based type is easily traversable front to back, as it’s a descendant of
This way, we can use
Stream pipelines, and create arrays from any collection by calling
For the inverse direction, back to front, there’s no easy way or trick available.
That means, for example, that if we have to deal with a
LinkedHashSet, we have to traverse the whole collection to get to the last element.
Until Java 21 and Sequenced Collections!
Sequenced Collection Types
JEP 431 introduces three new interfaces into the type hierarchy of the collection framework at strategic positions. Like many other features over the years, these interfaces inject their new functionality with the help of default methods, so everything is still backward compatible, and no one is forced to implement the methods by themselves unless we want a more specialized implementation.
The three new sequenced interfaces are:
SequencedCollection<E> extends Collection<E>
SequencedSet<E> extends SequencedCollection<E>, Set<E>
SequencedMap<K, V> extends Map<K, V>
SequencedCollection<E> interface looks like you would expect it, especially since all its methods, with the exception of
reversed(), were promoted from the pre-existing
Deque<E> type, to provide a known and uniform API:
remove... methods are optional and throw an
UnsupportedOperationException in their default implementation, to support unmodifiable collections.
get... methods behave like their brethren by throwing a
NoSuchElementException in the case of an empty collection.
SequencedSet<E> is based on
SequencedCollection<E> but has a covariant override for the return type of the
The mentioned behavior from before is also valid, as none of the default implementations from
SequencedCollection<E> are overridden.
Although differ conceptionally from other Collections as key-value-based constructs, there’s still a lot to gain from a sequenced approach.
SequencedCollection<E>, the type
SequencedMap<K, V> gains some of its functionality from promoting methods from a pre-existing type, in this case,
An interesting addition is the two promoted
poll... methods, as they give us an easy way to access the first or last entry AND remove it in one swoop.
Extending Java’s Collection Framework
As mentioned before, the three new types are retrofitted right into the pre-existing type hierarchy, to give us all the new goodies without breaking compatibility in any way:
Collection-based types change as follows:
SequencedCollectionas their immediate super-interface.
SortedSetnow is a direct descendant of
- The implementation
LinkedHashSetis now also a
SequencedSet. additionally implements SequencedSet
The changes for
Map were not as numerous, the type
SequenceMap is directly under
Map and above is the new super-interface for
SorterMap and an additional interface for the implementation
To match the general theme of the Collections Framework, there are also three new
static helper methods available on
The introduction of a well-defined encounter order and a uniform API across the board is a welcomed addition to Java in my opinion. It will provide developers with a more straightforward way to simplify commons collection tasks, and little by little, Java adds more convenience to its types.
As I talked about in previous articles, it might not be as concise and across-the-board compared to other languages, but implementing it in a straightforward and backward-compatible way is a trade-off I gladly accept.