Sequenced Collections Interview Questions & Answers
Java sequenced collections interview questions — SequencedCollection, SequencedSet, SequencedMap, getFirst/getLast, addFirst/addLast, reversed(), which collections implement the new interfaces, and migration from workarounds.
Sequenced collections (Java 21, JEP 431) introduce three new
interfaces — SequencedCollection, SequencedSet, and SequencedMap —
that give a uniform API for accessing the first and last elements and
for iterating in reverse order across all ordered collection types.
Before Java 21 each collection had its own non-uniform way to get the first or last element:
List<String> list = List.of("a", "b", "c");
list.get(0); // first element
list.get(list.size() - 1); // last element — verbose
Deque<String> deque = new ArrayDeque<>(list);
deque.peekFirst(); // first
deque.peekLast(); // last
SortedSet<String> sorted = new TreeSet<>(list);
sorted.first(); // first
sorted.last(); // last
SequencedCollection unifies these with getFirst() / getLast().
Rule of thumb: if you need the first or last element, check whether
the collection is a SequencedCollection and use the new API.
SequencedCollection<E> extends Collection<E> and adds:
| Method | Description |
|---|---|
getFirst() |
Returns the first element; throws NoSuchElementException if empty |
getLast() |
Returns the last element; throws NoSuchElementException if empty |
addFirst(E) |
Inserts at the beginning (optional — throws UnsupportedOperationException for fixed-size) |
addLast(E) |
Inserts at the end (optional) |
removeFirst() |
Removes and returns the first element (optional) |
removeLast() |
Removes and returns the last element (optional) |
reversed() |
Returns a reversed view of the collection |
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
System.out.println(list.getFirst()); // "a"
System.out.println(list.getLast()); // "c"
list.addFirst("z"); // ["z", "a", "b", "c"]
list.addLast("x"); // ["z", "a", "b", "c", "x"]
list.removeFirst(); // "z" removed
list.removeLast(); // "x" removed
Rule of thumb: getFirst()/getLast() replace get(0) and
get(list.size()-1) — use them for cleaner, more readable code.
SequencedSet<E> extends both SequencedCollection<E> and Set<E>,
adding no new methods but guaranteeing both the set contract (no
duplicates) and a defined encounter order.
Implementing classes:
LinkedHashSet— insertion-ordered set, implementsSequencedSetSortedSetsubtypes:TreeSet— sorted, implementsSequencedSetviaSortedSet(which extendsSequencedSet)
SequencedSet<String> set = new LinkedHashSet<>(List.of("b", "a", "c"));
System.out.println(set.getFirst()); // "b" — insertion order
System.out.println(set.getLast()); // "c"
System.out.println(set.reversed()); // ["c", "a", "b"] — reversed view
Rule of thumb: SequencedSet lets you treat LinkedHashSet and
TreeSet uniformly when you need first/last/reversed without knowing
the concrete type.
SequencedMap<K,V> extends Map<K,V> and adds methods to access
the first and last entries:
| Method | Description |
|---|---|
firstEntry() |
Returns (but does not remove) the first Map.Entry |
lastEntry() |
Returns the last Map.Entry |
pollFirstEntry() |
Removes and returns the first entry |
pollLastEntry() |
Removes and returns the last entry |
putFirst(K, V) |
Inserts/moves entry to the front (optional) |
putLast(K, V) |
Inserts/moves entry to the back (optional) |
reversed() |
Returns a reversed-order map view |
sequencedKeySet() |
Returns a SequencedSet<K> |
sequencedValues() |
Returns a SequencedCollection<V> |
sequencedEntrySet() |
Returns a SequencedSet<Map.Entry<K,V>> |
SequencedMap<String, Integer> map = new LinkedHashMap<>();
map.put("a", 1); map.put("b", 2); map.put("c", 3);
System.out.println(map.firstEntry()); // a=1
System.out.println(map.lastEntry()); // c=3
map.putFirst("z", 0); // {z=0, a=1, b=2, c=3}
Rule of thumb: SequencedMap lets you use LinkedHashMap and
TreeMap with a uniform first/last/reversed API without casting.
The new interfaces are retrofitted onto the existing type hierarchy:
| Collection | Implements |
|---|---|
ArrayList, LinkedList, ArrayDeque |
SequencedCollection |
LinkedHashSet |
SequencedSet |
TreeSet |
SequencedSet (via SortedSet) |
LinkedHashMap |
SequencedMap |
TreeMap |
SequencedMap (via SortedMap) |
List (interface) |
SequencedCollection |
Deque (interface) |
SequencedCollection |
SortedSet (interface) |
SequencedSet |
SortedMap (interface) |
SequencedMap |
SequencedCollection<Integer> col = new ArrayDeque<>(List.of(1, 2, 3));
col.getFirst(); // 1
col.getLast(); // 3
Rule of thumb: if the concrete type is ArrayList, LinkedHashSet,
TreeMap, etc. you already have the new methods — no migration needed.
reversed() returns a live, write-through view of the collection in
reverse encounter order. Mutations through the reversed view are reflected
in the original, and vice versa.
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
List<String> rev = list.reversed();
System.out.println(rev); // [c, b, a]
rev.addFirst("z"); // adds to the reversed view's front
System.out.println(list); // [a, b, c, z] — "z" is at the END of original
list.add("x"); // adds to original
System.out.println(rev); // [x, z, c, b, a] — reflected in reversed view
Rule of thumb: reversed() is a live view, not a copy — mutations
propagate both ways; if you need an independent copy, copy it explicitly.
For List implementations, getFirst() is equivalent to get(0) except
for the exception when the list is empty. get(0) throws
IndexOutOfBoundsException; getFirst() throws NoSuchElementException.
List<String> empty = new ArrayList<>();
empty.get(0); // IndexOutOfBoundsException: Index 0 out of bounds
empty.getFirst(); // NoSuchElementException
List<String> list = List.of("a", "b", "c");
list.get(0); // "a"
list.getFirst(); // "a" — same result
The semantic difference: IndexOutOfBoundsException signals a programming
error (index miscalculation); NoSuchElementException signals an empty
collection. getFirst() better expresses intent.
Rule of thumb: prefer getFirst() / getLast() over get(0) and
get(size-1) — the intent is clearer and the exception type is more
semantically correct.
Deque already had peekFirst()/peekLast(), pollFirst()/pollLast(),
addFirst()/addLast(). The new SequencedCollection essentially makes
these methods available on all ordered collections uniformly:
| Deque method | SequencedCollection equivalent |
|---|---|
peekFirst() |
getFirst() |
peekLast() |
getLast() |
pollFirst() |
removeFirst() |
pollLast() |
removeLast() |
addFirst(e) |
addFirst(e) |
addLast(e) |
addLast(e) |
Deque itself now extends SequencedCollection, so ArrayDeque and
LinkedList implement both and can be used interchangeably with either API.
Rule of thumb: Deque and SequencedCollection now share the first/
last API — prefer SequencedCollection in method signatures when you don't
need Deque-specific operations like push()/pop().
Yes. List now extends SequencedCollection, so all List instances —
including List.of() (immutable), Collections.unmodifiableList(), and
Arrays.asList() — have getFirst()/getLast():
List<String> immutable = List.of("a", "b", "c");
System.out.println(immutable.getFirst()); // "a" — works fine
System.out.println(immutable.getLast()); // "c"
// Mutation methods throw UnsupportedOperationException on immutable lists:
immutable.addFirst("z"); // UnsupportedOperationException
Rule of thumb: getFirst()/getLast() are safe on any List,
including immutable ones; mutation methods follow the same modifiability
rules as before.
Each collection type needed a different API:
// List — verbose index arithmetic:
String first = list.get(0);
String last = list.get(list.size() - 1);
// LinkedList (as Deque) — dedicated methods:
String first = ((LinkedList<String>) list).getFirst();
// ArrayDeque:
String first = deque.peekFirst();
String last = deque.peekLast();
// SortedSet / TreeSet:
String first = sortedSet.first();
String last = sortedSet.last();
// Iterating in reverse — no unified API:
Collections.reverse(list); // mutates the list!
// Or:
ListIterator<String> it = list.listIterator(list.size());
while (it.hasPrevious()) System.out.println(it.previous());
SequencedCollection replaces all of these with getFirst(), getLast(),
and reversed().
Rule of thumb: if you wrote list.get(list.size()-1) before Java 21,
replace it with list.getLast() — it is shorter and communicates intent.
Use SequencedCollection<E> (or SequencedMap<K,V>) in method signatures
when your method specifically needs first/last access or reverse
iteration but doesn't need to know the concrete type:
// Accept any ordered collection with first/last semantics:
static <T> T middle(SequencedCollection<T> col) {
// Use getFirst/getLast without caring if it's ArrayList or LinkedHashSet
if (col.isEmpty()) throw new NoSuchElementException();
// ... navigate to middle via iterator
}
// Too narrow — only works for List:
static <T> T middle(List<T> list) { ... }
// Too broad — Collection doesn't guarantee order:
static <T> T middle(Collection<T> col) { ... } // getFirst() doesn't exist
Rule of thumb: prefer SequencedCollection over List in signatures
when order and first/last access matter but random index access (get(i))
does not.
More Modern Java interview questions
More ways to practice
The self-quiz is live. Get notified when mock interviews and new question packs drop.