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).
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
Aprovéchalas siempre que escribas código nuevo sobre listas, deques, sets y maps con orden.
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.