Sequenced Collections Java 21
flowchart TB
Seq[SequencedCollection 21] --> List[List]
Seq --> SeqSet[SequencedSet]
Seq --> SeqMap[SequencedMap]
SeqSet --> LHS[LinkedHashSet]
SeqSet --> TS[TreeSet]
SeqMap --> LHM[LinkedHashMap]
SeqMap --> TM[TreeMap]
Seq --> First[getFirst getLast]
Seq --> Add[addFirst addLast]
Seq --> Rev[reversed vista invertida]
El problema histórico del Collections Framework
El Collections Framework, diseñado en Java 2 (1998), tenía una inconsistencia notable: muchas colecciones tienen un orden de encuentro bien definido, pero las operaciones para acceder al primer y último elemento eran distintas según la clase concreta.
// Para obtener el primer elemento: una forma distinta en cada clase
list.get(0); // ArrayList, LinkedList
linkedHashSet.iterator().next(); // LinkedHashSet: sin método directo
treeSet.first(); // TreeSet: método específico
deque.peekFirst(); // Deque: método específico
// Para el último
list.get(list.size() - 1);
treeSet.last();
deque.peekLast();
Añadir al principio de una lista también era incómodo:
list.add(0, elemento); // ArrayList: funciona pero O(n)
linkedList.addFirst(elemento); // LinkedList tiene el método
linkedHashSet.addFirst(...); // no existía
Java 21 introduce tres nuevas interfaces: SequencedCollection, SequencedSet y SequencedMap: que unifican estas operaciones.
SequencedCollection<E>
La interfaz SequencedCollection<E> extiende Collection<E> y añade:
interface SequencedCollection<E> extends Collection<E> {
void addFirst(E e);
void addLast(E e);
E getFirst();
E getLast();
E removeFirst();
E removeLast();
SequencedCollection<E> reversed();
}
Implementaciones existentes que la adoptan:
ArrayListLinkedList(ya teníaaddFirst/addLast)ArrayDeque- Cualquier
Dequeimplementa ahoraSequencedCollection
Ejemplo:
List<String> lista = new ArrayList<>(List.of("b", "c", "d"));
lista.addFirst("a"); // [a, b, c, d]
lista.addLast("e"); // [a, b, c, d, e]
String primero = lista.getFirst(); // "a"
String ultimo = lista.getLast(); // "e"
lista.removeFirst(); // [b, c, d, e]
lista.removeLast(); // [b, c, d]
SequencedCollection<String> reversed = lista.reversed(); // vista: [d, c, b]
Vista invertida
reversed() devuelve una vista (no una copia) del orden opuesto. Modificar la vista modifica el original:
List<Integer> original = new ArrayList<>(List.of(1, 2, 3, 4, 5));
SequencedCollection<Integer> reverso = original.reversed();
// Recorrer en orden inverso sin copiar
for (int n : reverso) {
System.out.println(n); // 5, 4, 3, 2, 1
}
// Modificar a través de la vista
reverso.addFirst(0); // añade al "primero" del reverso = al FINAL del original
// original ahora: [1, 2, 3, 4, 5, 0]
SequencedSet<E>
Extiende Set<E> y SequencedCollection<E>. Proporciona los mismos métodos pero sobre conjuntos con orden definido.
Implementaciones:
LinkedHashSet: orden de inserciónTreeSet: orden natural o por comparator
SequencedSet<String> set = new LinkedHashSet<>();
set.addLast("a");
set.addLast("b");
set.addLast("c");
set.addFirst("zero");
System.out.println(set); // [zero, a, b, c]
set.reversed().forEach(System.out::println); // c, b, a, zero
Para TreeSet, addFirst/addLast lanzan UnsupportedOperationException porque el orden lo determina el comparador (no puedes "forzar" la posición). Pero getFirst, getLast, removeFirst, removeLast y reversed sí funcionan.
SequencedMap<K, V>
Extiende Map<K, V> añadiendo:
interface SequencedMap<K, V> extends Map<K, V> {
V putFirst(K key, V value);
V putLast(K key, V value);
Map.Entry<K, V> firstEntry();
Map.Entry<K, V> lastEntry();
Map.Entry<K, V> pollFirstEntry();
Map.Entry<K, V> pollLastEntry();
SequencedMap<K, V> reversed();
SequencedSet<K> sequencedKeySet();
SequencedCollection<V> sequencedValues();
SequencedSet<Map.Entry<K, V>> sequencedEntrySet();
}
Implementaciones:
LinkedHashMapTreeMap
SequencedMap<String, Integer> mapa = new LinkedHashMap<>();
mapa.put("a", 1);
mapa.put("b", 2);
mapa.put("c", 3);
mapa.putFirst("zero", 0); // [zero=0, a=1, b=2, c=3]
Map.Entry<String, Integer> primera = mapa.firstEntry(); // zero=0
Map.Entry<String, Integer> ultima = mapa.lastEntry(); // c=3
// Vista invertida
SequencedMap<String, Integer> reverso = mapa.reversed();
reverso.forEach((k, v) -> System.out.println(k + "=" + v));
// c=3, b=2, a=1, zero=0
Casos de uso reales
Cola LIFO / stack con LinkedList
Antes, Stack era la clase obsoleta. Con SequencedCollection tienes una API clara:
SequencedCollection<String> pila = new LinkedList<>();
pila.addFirst("a"); // push
pila.addFirst("b");
pila.addFirst("c");
String top = pila.getFirst(); // peek: "c"
String pop = pila.removeFirst(); // pop: "c"
Cache LRU con LinkedHashMap
LinkedHashMap mantiene orden de inserción; con reversed() y acceso a primer/último es trivial implementar una cache LRU:
SequencedMap<String, Producto> cache = new LinkedHashMap<>();
void accesar(String clave, Producto p) {
cache.remove(clave); // quitar si existía
cache.putLast(clave, p); // ponerlo como más reciente
if (cache.size() > MAX) {
cache.pollFirstEntry(); // eliminar el menos reciente
}
}
Iterar en orden inverso sin copiar
Antes de Java 21, para recorrer una lista al revés se creaba una copia invertida o se usaba un ListIterator manualmente:
// Antes
for (int i = lista.size() - 1; i >= 0; i--) {
process(lista.get(i));
}
// Con Java 21
for (var x : lista.reversed()) {
process(x);
}
TreeMap/TreeSet invertidos
SequencedMap<Integer, String> scores = new TreeMap<>();
scores.put(85, "Ana");
scores.put(92, "Bob");
scores.put(78, "Carmen");
// Top 3 scores (orden descendente)
scores.reversed().entrySet().stream()
.limit(3)
.forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));
Qué interfaces implementan qué
| Clase | SequencedCollection | SequencedSet | SequencedMap |
|-------|:---:|:---:|:---:|
| ArrayList | ✅ | | |
| LinkedList | ✅ | | |
| ArrayDeque | ✅ | | |
| PriorityQueue | | | |
| HashSet | | | |
| LinkedHashSet | ✅ | ✅ | |
| TreeSet | ✅ | ✅ | |
| HashMap | | | |
| LinkedHashMap | | | ✅ |
| TreeMap | | | ✅ |
Nota: HashSet, HashMap y PriorityQueue no implementan las interfaces secuenciadas porque no tienen orden definido (HashSet/HashMap) o el orden depende del estado interno (PriorityQueue).
Caso B2B: cola de eventos en banca y telco
En entornos bancarios donde vuestro equipo procesa una cola de eventos transaccionales con orden estricto de llegada (por ejemplo, una pasarela SEPA Instant que ingresa cargos y abonos en milésimas de segundo), las colecciones secuenciadas eliminan el código defensivo que antes mezclaba Deque, LinkedList y comprobaciones de tamaño. La organización gana legibilidad y reduce la superficie para fallos por confusión entre peek() y peekFirst() durante guardias de incidencias.
En telco, la implementación de un buffer LRU para sesiones de usuario móvil (cache de tokens OAuth en pasarelas API que reciben centenares de miles de peticiones por segundo) se simplifica con LinkedHashMap y pollFirstEntry(). Antes de Java 21, equipos enteros mantenían wrappers propios sobre LinkedHashMap con removeEldestEntry; ahora la misma lógica cabe en cinco líneas y queda explícita en revisiones de código.
En retail, sistemas de fidelización que muestran los últimos cinco productos visitados por el cliente sobre LinkedHashSet<String> aprovechan set.reversed().stream().limit(5) sin reconstruir colecciones intermedias, lo que importa cuando el catálogo recibe rachas de tráfico durante campañas de Black Friday.
Versiones y disponibilidad
SequencedCollection, SequencedSet y SequencedMap están disponibles desde Java 21 LTS (septiembre 2023) y forman parte del JDK 21+. Java 25 LTS (septiembre 2025) las mantiene sin cambios incompatibles. Son interfaces estables de la plataforma, fuera de cualquier --enable-preview. El JEP de referencia es el JEP 431 (Sequenced Collections), aceptado y entregado en JDK 21.
Para vuestra organización, esto implica que no hay flag de compilación ni dependencia adicional: basta con compilar contra --release 21 o superior. En proyectos con base instalada en Java 17 LTS (frecuente en banca y AAPP por ciclos de migración), el uso de estas interfaces obliga a elevar el bytecode mínimo, decisión que conviene coordinar con la oficina de arquitectura.
Anti-patrones y pitfalls
Asumir que addFirst siempre funciona en Set. En TreeSet, las inserciones por posición lanzan UnsupportedOperationException porque el orden lo determina el Comparator. Si vuestro código recibe un SequencedSet genérico desde otra capa, conviene documentar la implementación esperada o capturar la excepción en pruebas de contrato.
Confundir vista con copia. reversed() devuelve una vista en vivo: cualquier mutación se refleja en el original. En código concurrente sin sincronización externa esto provoca ConcurrentModificationException con la misma probabilidad que iterar el original. Si necesitáis un snapshot, copiad explícitamente con new ArrayList<>(coleccion.reversed()).
Sustituir Stack por LinkedList sin medir. Aunque LinkedList ofrece la API correcta para una pila LIFO, su rendimiento en cachés modernas es inferior al de ArrayDeque por la fragmentación de memoria de los nodos enlazados. Para pilas calientes en bucles internos, ArrayDeque con addFirst/removeFirst rinde mejor. Esto se nota en cargas de microservicios con SLA por debajo de 50 ms.
Olvidar que pollFirstEntry() modifica el mapa. Algunos equipos lo usan para "consultar" el primer elemento y se sorprenden cuando desaparece de la cache. Para inspección sin efectos laterales, usad firstEntry().
Comparativa con alternativas
Frente a Guava (Iterables.getFirst, Iterables.getLast), las interfaces secuenciadas evitan la dependencia externa y operan en O(1) sobre estructuras enlazadas, mientras que Iterables.getLast puede recorrer toda la colección si no detecta List.
Frente a Apache Commons Collections (CollectionUtils, ListUtils.reverse), Java 21 ofrece la misma capacidad sin librerías adicionales y con la garantía de mantenimiento del JDK durante todo el ciclo LTS (al menos hasta 2031 para Java 21).
Frente a Kotlin (first(), last(), reversed() en Collection), Java 21 cierra parte de la brecha de ergonomía sin necesidad de cambiar de lenguaje, lo cual conviene a equipos con base de código histórica en Java que no quieren adoptar Kotlin solo por sintaxis de colecciones.
Documentación oficial
La especificación canónica está en la documentación de Oracle de la API Java SE: paquete java.util, interfaces SequencedCollection, SequencedSet y SequencedMap. El JEP 431 detalla la motivación y la lista exhaustiva de métodos por implementación.
Resumen
Las interfaces secuenciadas de Java 21 completan el Collections Framework. Ya no hay que recordar qué clase tiene qué método para acceder al primer o último elemento: todas las que tienen orden definido comparten la misma API uniforme.
Para código profesional Java 21+, estos métodos son la forma canónica de operar con orden:
addFirst/addLast: inserción con posicióngetFirst/getLast: acceso directoremoveFirst/removeLast: extracciónreversed(): vista invertida
Aprovechad estas interfaces siempre que vuestro equipo escriba código nuevo sobre listas, deques, sets y maps con orden definido. En proyectos B2B con presión por mantenibilidad, la consistencia de la API reduce el coste de revisión y el riesgo de bugs por confusión entre métodos heredados de cada implementación.
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Java es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Java
Explora más contenido relacionado con Java y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Conocer las interfaces SequencedCollection, SequencedSet y SequencedMap. Usar los nuevos métodos uniformes: addFirst, addLast, getFirst, getLast, removeFirst, removeLast. Aplicar reversed() para obtener vistas invertidas de colecciones. Integrar estas interfaces con implementaciones existentes (ArrayList, LinkedList, LinkedHashSet, LinkedHashMap, TreeSet, TreeMap). Entender por qué este refactor faltaba en el Collections Framework.