Comprehensive Guide to Sequenced Collections in Java
Target Java versions:
- Preview / Incubation: Early work in Java 20
- Final / Standard: Java 21 – JEP 431: Sequenced CollectionsSequenced Collections introduce new interfaces in
java.utilto give a uniform, explicit way to work with ordered collections:
SequencedCollection<E>SequencedSet<E>SequencedMap<K, V>Before this, Java APIs were inconsistent about “first/last” elements and iteration order.
1. Motivation: Why Sequenced Collections?
Before Java 21:
Listhas index-based operations:get(0),get(size-1).DequehasaddFirst,addLast,getFirst,getLast, etc.SortedSet/NavigableSethavefirst,last.Maphas no standard “first/last entry” concept (exceptSortedMap/NavigableMapwithfirstEntry/lastEntry).Setgenerally has no ordering contract (exceptLinkedHashSetwith insertion order, but API doesn’t expose first/last explicitly).
The result: no common interface to talk about “the first and last element” of an ordered collection, even though many collections are naturally ordered.
Sequenced Collections fix this by:
- Providing an explicit concept of encounter order (the order you see elements when iterating).
- Adding a uniform API for:
- First element
- Last element
- Adding/removing at both ends
- Reversed view
2. The New Interfaces
2.1. SequencedCollection<E>
- Extends
Collection<E>. - Adds operations for handling the first and last elements.
- Introduces a reversed view.
Key methods (conceptually):
public interface SequencedCollection<E> extends Collection<E> {
E getFirst();
E getLast();
E removeFirst();
E removeLast();
void addFirst(E e);
void addLast(E e);
SequencedCollection<E> reversed();
}
(Exact signatures may include default implementations where appropriate.)
This unifies many patterns that were previously scattered across List, Deque, etc.
2.2. SequencedSet<E>
- Extends both
Set<E>andSequencedCollection<E>.
Conceptually:
public interface SequencedSet<E> extends Set<E>, SequencedCollection<E> {
SequencedSet<E> reversed();
}
Intended for sets with a well-defined encounter order, e.g.:
LinkedHashSet– insertion orderSortedSet/NavigableSet– sorted order
2.3. SequencedMap<K, V>
- Extends
Map<K, V>. - Adds methods for first/last entries, reversed view, and insertion at front/back.
Conceptually:
public interface SequencedMap<K, V> extends Map<K, V> {
Map.Entry<K, V> firstEntry();
Map.Entry<K, V> lastEntry();
Map.Entry<K, V> pollFirstEntry();
Map.Entry<K, V> pollLastEntry();
V putFirst(K key, V value);
V putLast(K key, V value);
SequencedMap<K, V> reversed();
}
This gives a consistent API for maps that maintain order, e.g.:
LinkedHashMapSortedMap/NavigableMapimplementations, etc.
3. Encounter Order
Encounter order = the order in which elements are encountered when iterating over the collection.
Key points:
List→ encounter order = index order (0…size-1).LinkedHashSet→ insertion order (or access order if configured).SortedSet/SortedMap→ sorted according to comparator / natural order.HashSet/HashMap→ no guaranteed encounter order → they do not implementSequenced*.
Sequenced collections rely on this concept to define:
getFirst()→ first element in encounter order.getLast()→ last element in encounter order.reversed()→ view whose encounter order is the reverse of the original.
4. Implementations in the Standard Library
With Java 21, many JDK classes now implement the new interfaces:
List<E>→SequencedCollection<E>Deque<E>→SequencedCollection<E>(most likely)LinkedHashSet<E>→SequencedSet<E>SortedSet<E>/NavigableSet<E>implementations →SequencedSet<E>LinkedHashMap<K, V>→SequencedMap<K, V>SortedMap<K, V>/NavigableMap<K, V>implementations →SequencedMap<K, V>
Non-sequenced:
HashSet,HashMap– still not sequenced; they do not guarantee encounter order.
5. Key Methods and Semantics
5.1. getFirst() and getLast()
E first = coll.getFirst();
E last = coll.getLast();
collis aSequencedCollection<E>.- Throws an exception (typically
NoSuchElementException) if empty.
Example:
SequencedCollection<String> sc = (SequencedCollection<String>) new ArrayList<>(List.of("A", "B", "C"));
System.out.println(sc.getFirst()); // "A"
System.out.println(sc.getLast()); // "C"
For List, this typically maps to:
getFirst()→get(0)getLast()→get(size()-1)
5.2. addFirst(E e) and addLast(E e)
coll.addFirst("X"); // insert at the beginning
coll.addLast("Y"); // append at the end
- For
List,addFirstwould be likeadd(0, e). - For
Deque, they map naturally toaddFirst/addLast.
Example:
SequencedCollection<Integer> sc = (SequencedCollection<Integer>) new LinkedList<>(List.of(1, 2, 3));
sc.addFirst(0); // [0, 1, 2, 3]
sc.addLast(4); // [0, 1, 2, 3, 4]
5.3. removeFirst() and removeLast()
E removedFirst = coll.removeFirst();
E removedLast = coll.removeLast();
- Remove and return the first / last element.
- Throw
NoSuchElementExceptionif empty.
For Deque, these correspond to removeFirst / removeLast.
For List, they’re like remove(0) / remove(size-1).
5.4. reversed() — Reversed View
reversed() is a view, not a copy.
SequencedCollection<String> sc = (SequencedCollection<String>) new ArrayList<>(List.of("A", "B", "C"));
SequencedCollection<String> rev = sc.reversed();
System.out.println(rev); // logically ["C", "B", "A"]
Important:
- Operations on the reversed view affect the original collection, and vice versa.
- This is similar to how
Collections.unmodifiableListreturns a view.
Example behavior:
SequencedCollection<String> sc = (SequencedCollection<String>) new LinkedList<>(List.of("A", "B", "C"));
SequencedCollection<String> rev = sc.reversed();
rev.addFirst("Z"); // adds to *end* of original sc → sc = [A, B, C, Z]
rev.addLast("X"); // adds to *beginning* of original sc → sc = [X, A, B, C, Z]
So:
- In
revorder:[Z, C, B, A, X] - In
scorder:[X, A, B, C, Z]
Reversed is conceptually “flipped view” of the same underlying data.
6. Sequenced Maps: Examples
6.1. Basic Use
SequencedMap<String, Integer> map =
(SequencedMap<String, Integer>) new LinkedHashMap<String, Integer>();
map.putLast("b", 2);
map.putFirst("a", 1);
map.putLast("c", 3);
System.out.println(map.firstEntry()); // a=1
System.out.println(map.lastEntry()); // c=3
6.2. firstEntry, lastEntry, pollFirstEntry, pollLastEntry
Map.Entry<String, Integer> first = map.firstEntry();
Map.Entry<String, Integer> last = map.lastEntry();
Map.Entry<String, Integer> removedFirst = map.pollFirstEntry(); // remove+return
Map.Entry<String, Integer> removedLast = map.pollLastEntry(); // remove+return
Typical behavior:
firstEntry()/lastEntry()– view of first/last mapping; no structural modification.pollFirstEntry()/pollLastEntry()– remove first/last mapping and return it; returnsnullif empty.
6.3. putFirst and putLast
map.putLast("x", 10); // put (or move) mapping to end
map.putFirst("y", 20); // put (or move) mapping to start
Behaviors:
- If key already exists:
- Value is updated.
- Entry moved to front/back accordingly.
- If key is new:
- Entry inserted at front/back.
This is particularly useful for LRU-like structures and custom caches.
6.4. reversed() on SequencedMap
SequencedMap<String, Integer> rev = map.reversed();
- Gives a view of the same mappings in reversed encounter order.
- Put/remove on the reversed view affects the underlying map.
Example:
map.putLast("a", 1);
map.putLast("b", 2);
map.putLast("c", 3);
SequencedMap<String, Integer> rev = map.reversed();
rev.putFirst("z", 0); // add "z" as *last* in original map
rev.putLast("x", 9); // add "x" as *first* in original map
7. Sequenced Sets: Examples
7.1. LinkedHashSet as SequencedSet
SequencedSet<String> set =
(SequencedSet<String>) new LinkedHashSet<>(List.of("A", "B", "C"));
System.out.println(set.getFirst()); // "A"
System.out.println(set.getLast()); // "C"
set.addFirst("Z"); // now order: Z, A, B, C (no duplicates)
set.addLast("Y"); // Z, A, B, C, Y
addFirst / addLast preserve uniqueness semantics:
- If element already exists, you must check how the concrete implementation handles it:
- Typically: move to front or back (similar to LinkedHashMap semantics),
- Or ignore re-insertion.
7.2. SortedSet / NavigableSet
For sorted sets, “first/last” is sorted order, not insertion order:
SequencedSet<Integer> s = (SequencedSet<Integer>) new TreeSet<>(Set.of(3, 1, 2));
System.out.println(s.getFirst()); // 1
System.out.println(s.getLast()); // 3
reversed() view will traverse in descending order.
8. Interactions With Streams and Iteration
Sequenced collections integrate smoothly with existing iteration patterns:
for-eachloops respect encounter order.stream()preserves encounter order (as before).reversed()reversed view preserves its own encounter order when streamed.
Example:
SequencedCollection<String> sc =
(SequencedCollection<String>) new ArrayList<>(List.of("A", "B", "C"));
sc.stream().forEach(System.out::println);
// A B C
sc.reversed().stream().forEach(System.out::println);
// C B A
9. Design Intent and Benefits
9.1. Unified API Across Ordered Collections
Previously, operations like “add at front” or “get last” were scattered:
Dequehad its own methods.Listneeded index-based work.- Sorted sets/maps had
first/lastbut different naming patterns.
Now:
addFirst,addLast,getFirst,getLast,removeFirst,removeLast,reversedare standardized for all sequenced types.
9.2. Cleaner, More Expressive Code
Examples:
Before:
List<String> list = new ArrayList<>();
list.add(0, "first");
list.add("last");
String first = list.get(0);
String last = list.get(list.size() - 1);
After:
SequencedCollection<String> sc = (SequencedCollection<String>) list;
sc.addFirst("first");
sc.addLast("last");
String first = sc.getFirst();
String last = sc.getLast();
9.3. Fewer Special-Case APIs
Instead of introducing new class-specific methods, the JDK uses the new interfaces.
10. Limitations and Things to Watch Out For
10.1. Not All Collections are Sequenced
HashSet,HashMap, and some others do not implement sequenced interfaces.- They do not guarantee an encounter order.
If you need sequenced behavior, use:
LinkedHashSetLinkedHashMapList,Deque- Sorted / Navigable collections, etc.
10.2. Reversed Views Are Live
reversed() returns live views.
Things to remember:
- Modifications through one view are reflected in the other.
- Removing/adding via
reversed()may be confusing if you don’t mentally track the semantics.
If you want an independent reversed copy:
SequencedCollection<String> rc = sc.reversed();
List<String> copy = new ArrayList<>(rc); // copy
10.3. Exceptions on Empty Collections
getFirst, getLast, removeFirst, removeLast:
- Typically throw
NoSuchElementExceptionwhen the collection is empty. - Use
isEmpty()to guard, or better, usepoll*-style APIs where available (on maps).
10.4. Performance Considerations
- For
ArrayList: addLastis generally O(1) amortized.addFirstmay be O(n) due to element shifting.- For
LinkedList/Deque: addFirst/addLastare generally O(1).
Sequenced interfaces define semantics, not performance characteristics; you must still pick an appropriate implementation.
11. Best Practices & Patterns
✔ Prefer Sequenced Interfaces in APIs
void process(SequencedCollection<String> coll) { ... }
instead of:
void process(List<String> list) { ... }
if you only rely on “sequence” semantics rather than list-specific ones.
Similarly:
void process(SequencedMap<K, V> map) { ... }
to allow callers to pass LinkedHashMap, TreeMap, etc.
✔ Use Reversed Views Instead of Manual Reversal When You Want a View
SequencedCollection<E> rev = coll.reversed();
instead of:
List<E> copy = new ArrayList<>(coll);
Collections.reverse(copy);
The view is lazy and updates with the original.
✔ Model Queues/Deques With SequencedCollection
Many queue or deque-like operations can now use SequencedCollection instead of a specific Deque or List.
❌ Don’t Assume Hash-Based Collections Are Sequenced
If your code depends on encounter order:
- Don’t use
HashMap/HashSetdirectly. - Use
LinkedHashMap/LinkedHashSetor other ordered variants.
12. Typical Interview Questions (With Answers)
Q1. What are Sequenced Collections?
A: A set of new interfaces (SequencedCollection, SequencedSet, SequencedMap) introduced in Java 21 that unify operations on collections with a well-defined encounter order (first/last, add/remove at ends, reversed view).
Q2. Which Java version introduced Sequenced Collections?
A: Java 21, via JEP 431.
Q3. Name key methods provided by SequencedCollection.
A:
- addFirst, addLast
- getFirst, getLast
- removeFirst, removeLast
- reversed
Q4. Do HashSet or HashMap implement Sequenced interfaces?
A: No. They do not guarantee a stable encounter order and therefore are not sequenced.
Q5. What does reversed() return?
A: A live view of the same collection or map, but with the encounter order reversed.
Changes through either view are reflected in the other.
Q6. How do Sequenced Collections help with API design?
A: They provide a generic, uniform way to express “ordered collection” requirements in method signatures without tying the API to specific implementations (List, Deque, LinkedHashMap, etc.).
13. Summary
Sequenced Collections are a key enhancement in modern Java:
- Introduced in Java 21 to unify and clarify the notion of ordered collections.
- Provide consistent first/last/add/remove/reversed operations for:
- Collections →
SequencedCollection - Sets →
SequencedSet - Maps →
SequencedMap - Make APIs more expressive and easier to reason about.
- Work seamlessly with existing implementations like
List,Deque,LinkedHashSet,LinkedHashMap, and sorted collections.
They are especially important for interview preparation when discussing:
- New Java language & library features
- Collections framework evolution
- API design and encounter order semantics
This guide should give you enough detail to use Sequenced Collections confidently in both interviews and real projects.