SequencedCollection, SequencedSet y SequencedMap (Java 21)

Avanzado
Java
Java
Actualizado: 18/04/2026

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:

  • ArrayList
  • LinkedList (ya tenía addFirst/addLast)
  • ArrayDeque
  • Cualquier Deque implementa ahora SequencedCollection

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ón
  • TreeSet: 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:

  • LinkedHashMap
  • TreeMap
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ón
  • getFirst / getLast: acceso directo
  • removeFirst / removeLast: extracción
  • reversed(): vista invertida

Aprovéchalas siempre que escribas código nuevo sobre listas, deques, sets y maps con orden.

Alan Sastre - Autor del tutorial

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.