Definition
SequencedCollection– Base interface addinggetFirst(),getLast(),addFirst(),addLast(),removeFirst(),removeLast(), andreversed()for any collection with a defined encounter order.SequencedSet– ExtendsSequencedCollectionfor sets with unique elements, refiningreversed()to return aSequencedSet.SequencedMap– Map counterpart addingfirstEntry(),lastEntry(),pollFirstEntry(),pollLastEntry(),putFirst(),putLast(), andreversed().- Retrofitted –
List,Deque,LinkedHashSet,LinkedHashMap, and theNavigableSet/NavigableMapfamilies now implement these interfaces. reversed()view – Returns a view, not a copy, so iterating walks backwards and changes write through to the original.
Imagine National Bank of India keeps several ordered queues: a line of customers at the counter, a ledger of transactions in date order, and a list of recent logins. Before Java 21, asking "who is first" and "who is last" worked differently for each: for one you called a method, for another you did size minus one, and for a set you had to iterate the whole thing just to reach the end. Sequenced Collections are like a single standard rule posted on every ordered queue: "to see the front, say getFirst; to see the back, say getLast; to read it backwards, say reversed."
Understanding the Concepts
What gap did Sequenced Collections fill?
Before Java 21, order was a concept scattered across types with no shared interface. A List gave its first element with get(0) and its last with get(size() - 1). A Deque had getFirst() and getLast(). A LinkedHashSet had a defined iteration order but no direct way to get the last element except iterating to the end. A LinkedHashMap and a sorted map had order too, but accessing the ends was inconsistent.
package com.bank.service;
import java.util.*;
public class BeforeSequencedCollections {
public void inconsistentAccess() {
// List: index arithmetic
List<String> accounts = List.of("SAV2001", "CUR3001", "SAV2002");
String first = accounts.get(0);
String last = accounts.get(accounts.size() - 1); // error-prone
// Deque: different methods
Deque<String> queue = new ArrayDeque<>(accounts);
String dFirst = queue.getFirst();
String dLast = queue.getLast();
// LinkedHashSet: no direct last-element access
Set<String> recent = new LinkedHashSet<>(accounts);
String sFirst = recent.iterator().next();
// No getLast()! Must iterate to the end
}
}
What are the new interfaces and methods?
SequencedCollection is the base, adding uniform first and last access. SequencedSet extends it for unique elements. SequencedMap is the map counterpart.
package com.bank.service;
import java.util.*;
import java.math.BigDecimal;
public class SequencedCollectionDemo {
public void demonstrateNewMethods() {
// SequencedCollection: getFirst, getLast, reversed
List<String> transactions = new ArrayList<>(
List.of("TXN-001", "TXN-002", "TXN-003")
);
String oldest = transactions.getFirst(); // TXN-001
String newest = transactions.getLast(); // TXN-003
// SequencedSet: unique elements with order
SequencedSet<String> recentAccounts = new LinkedHashSet<>();
recentAccounts.addFirst("SAV2001");
recentAccounts.addLast("CUR3001");
String lastUsed = recentAccounts.getLast(); // CUR3001
// SequencedMap: first and last entries
SequencedMap<String, BigDecimal> balances =
new LinkedHashMap<>();
balances.put("SAV2001", new BigDecimal("50000.00"));
balances.put("CUR3001", new BigDecimal("120000.00"));
balances.put("SAV2002", new BigDecimal("75000.00"));
Map.Entry<String, BigDecimal> first =
balances.firstEntry();
Map.Entry<String, BigDecimal> last =
balances.lastEntry();
System.out.println("First: " + first);
System.out.println("Last: " + last);
}
}
First: SAV2001=50000.00
Last: SAV2002=75000.00
How does the reversed() view work?
The reversed() method returns a view, not a copy. Iterating it walks the original in reverse, and for mutable collections, changes through the view write back to the original.
package com.bank.service;
import java.util.*;
import java.math.BigDecimal;
public class ReversedViewDemo {
public void newestFirstStatement() {
List<String> transactions = new ArrayList<>(
List.of("Deposit 10000", "Transfer 5000", "Withdrawal 2000")
);
// View, not a copy: walks backwards
List<String> newestFirst = transactions.reversed();
for (String txn : newestFirst) {
System.out.println(txn);
}
// Output:
// Withdrawal 2000
// Transfer 5000
// Deposit 10000
// Changes through the view write back
newestFirst.set(0, "Withdrawal 3000");
System.out.println(transactions.getLast());
// Prints: Withdrawal 3000
}
}
Which existing types were retrofitted?
| Type | Now Implements |
|---|---|
| List | SequencedCollection |
| Deque | SequencedCollection |
| LinkedHashSet | SequencedSet |
| SortedSet / NavigableSet | SequencedSet |
| LinkedHashMap | SequencedMap |
| SortedMap / NavigableMap | SequencedMap |
Existing collections gained the new methods without changing their declared types.
What are the edge cases and exceptions?
getFirst() and getLast() throw NoSuchElementException on an empty collection. addFirst() and addLast() on a sorted set or map throw UnsupportedOperationException because you cannot force a position against the comparator's order.
package com.bank.service;
import java.util.*;
public class SequencedEdgeCases {
public void emptyCollectionAccess() {
List<String> empty = new ArrayList<>();
try {
empty.getFirst(); // NoSuchElementException
} catch (NoSuchElementException e) {
System.out.println("Empty list: " + e.getMessage());
}
}
public void sortedSetPositionConflict() {
SequencedSet<String> sorted = new TreeSet<>();
sorted.add("CUR3001");
sorted.add("SAV2001");
try {
sorted.addFirst("ZZZ9999");
// UnsupportedOperationException: cannot force position
} catch (UnsupportedOperationException e) {
System.out.println("Sorted set: " + e.getMessage());
}
}
}
How is this different from using get(0) and get(size-1)?
| Operation | Before Java 21 | Java 21+ |
|---|---|---|
| First element (List) | list.get(0) | list.getFirst() |
| Last element (List) | list.get(list.size() - 1) | list.getLast() |
| First element (Set) | set.iterator().next() | set.getFirst() |
| Last element (Set) | Iterate entire set | set.getLast() |
| Reverse iteration | Copy + Collections.reverse | collection.reversed() |
| First map entry | Iterate to find | map.firstEntry() |
What about SequencedMap-specific methods?
SequencedMap adds firstEntry(), lastEntry(), pollFirstEntry() (retrieves and removes), pollLastEntry(), putFirst(), putLast(), and sequencedKeySet(), sequencedValues(), sequencedEntrySet() for ordered views.
package com.bank.service;
import java.util.*;
import java.math.BigDecimal;
public class SequencedMapDemo {
public void bankingMapOperations() {
SequencedMap<String, BigDecimal> recentDeposits =
new LinkedHashMap<>();
recentDeposits.put("TXN-001", new BigDecimal("10000.00"));
recentDeposits.put("TXN-002", new BigDecimal("25000.00"));
recentDeposits.put("TXN-003", new BigDecimal("50000.00"));
// First and last entries
System.out.println("Earliest: " + recentDeposits.firstEntry());
System.out.println("Latest: " + recentDeposits.lastEntry());
// Poll removes and returns
Map.Entry<String, BigDecimal> removed =
recentDeposits.pollFirstEntry();
System.out.println("Removed: " + removed);
System.out.println("Remaining: " + recentDeposits.size());
}
}
What should a senior engineer know?
The feature adds no new data structures; it is purely a unifying API layered over existing ordered types. That is exactly why it is valuable: it removes a pile of index arithmetic and iterator boilerplate and makes ordered-collection code read the same everywhere. The reversed() view is a view, not a copy, which matters for performance with large collections.
Visual Overview
┌───────────────────────────────────────────────────────────┐ │ Sequenced Collection Interface Hierarchy │ ├───────────────────────────────────────────────────────────┤ │ │ │ SequencedCollection │ │ ┌─────────────────────┐ │ │ │ getFirst/getLast │ │ │ │ addFirst/addLast │ │ │ │ removeFirst/Last │ │ │ │ reversed() │ │ │ └──────┬──────┬──────┘ │ │ │ │ │ │ ┌───────────┘ └───────────┐ │ │ ▼ ▼ │ │ SequencedSet SequencedMap │ │ ┌──────────────┐ ┌──────────────────┐ │ │ │ reversed() │ │ firstEntry() │ │ │ │ → Seq.Set │ │ lastEntry() │ │ │ └──────────────┘ │ putFirst/putLast │ │ │ │ │ reversed()→Seq.Map│ │ │ │ └──────────────────┘ │ │ ▼ ▼ │ │ List, Deque, LinkedHashMap, │ │ LinkedHashSet, SortedMap, │ │ SortedSet, NavigableMap │ │ NavigableSet │ └───────────────────────────────────────────────────────────┘
Key Takeaway
Sequenced Collections, added in Java 21, are three new interfaces that give any collection with a defined encounter order one uniform API for first and last access and for reversal. SequencedCollection adds getFirst(), getLast(), addFirst(), addLast(), removeFirst(), removeLast(), and reversed(). SequencedSet refines this for unique elements. SequencedMap adds firstEntry(), lastEntry(), pollFirstEntry(), pollLastEntry(), putFirst(), putLast(), and reversed().
The gap they fill is that before Java 21, order was scattered across types with no shared interface. A List gave its first element with get(0) and its last with get(size() - 1). A Deque had getFirst() and getLast(). A LinkedHashSet had a defined iteration order but no direct way to reach the last element except iterating all the way to the end. There was no common type that said "I am ordered and I have a first and a last."
These interfaces were retrofitted into existing types, so List and Deque implement SequencedCollection, LinkedHashSet and the sorted-set family implement SequencedSet, and LinkedHashMap and the sorted-map family implement SequencedMap, all without changing declared types. The reversed() method returns a view rather than a copy, so iterating it walks the original backwards and changes through the view write back.
In banking work at National Bank of India this cleaned up ordered-collection code. A customer's transaction list exposed the most recent transaction with getLast() and a newest-first statement view with reversed(), instead of size-minus-one and manual reverse loops. A LinkedHashSet of recently used accounts gained direct first and last access. The senior details are that getFirst() and getLast() throw NoSuchElementException on an empty collection, and addFirst() or addLast() on a sorted set or map throws UnsupportedOperationException because position cannot override comparator order.
Remember one sentence: Sequenced Collections unify first, last, and reversed access across all ordered collection types with getFirst(), getLast(), and reversed(), eliminating inconsistent index arithmetic and iterator boilerplate.
---