CodeGym /Cursos /JAVA 25 SELF /Colecciones nuevas: SequencedCollection, SequencedSet, Se...

Colecciones nuevas: SequencedCollection, SequencedSet, SequencedMap

JAVA 25 SELF
Nivel 34 , Lección 4
Disponible

1. El problema del orden en las colecciones clásicas

En Java siempre ha habido colecciones que garantizan el orden de los elementos (por ejemplo, ArrayList, LinkedList, LinkedHashSet, LinkedHashMap) y otras en las que el orden no está garantizado (por ejemplo, HashSet, HashMap). Pero todas ellas tenían un inconveniente común: aunque algunas almacenan los elementos en un orden determinado, las interfaces estándar (List, Set, Map) no proporcionaban métodos universales para acceder al primer y al último elemento ni para invertir el orden.

Por ejemplo, si tienes List<String>, puedes obtener el primer elemento con list.get(0), pero en un Set o un Map ese truco ya no sirve — tendrás que usar iteradores o escribir código adicional. Convengamos en que no es muy cómodo ni favorece la legibilidad.

Es como si tuvieras un mueble con cajones y, para coger el primero o el último, tuvieras que volver a contar todos los cajones a mano cada vez. Sería genial tener unas asas especiales «primero» y «último», ¿verdad?

La aparición de SequencedCollection y de las interfaces relacionadas

En Java 21 aparecieron nuevas interfaces de colecciones:

  • SequencedCollection<E>
  • SequencedSet<E>
  • SequencedMap<K, V>

Estas interfaces amplían las colecciones estándar e introducen un enfoque unificado para trabajar con el orden de los elementos. Ahora puedes escribir código universal para cualquier colección en la que el orden importe, sin preocuparte por la implementación concreta.

¿Qué son?

  • SequencedCollection — es una colección cuyos elementos tienen un orden determinado y en la que puedes obtener fácilmente el primer y el último elemento, así como invertir el orden.
  • SequencedSet — lo mismo, pero para conjuntos (elementos únicos).
  • SequencedMap — lo mismo, pero para mapas (clave-valor).

¿Qué colecciones los implementan ahora?

En Java 21 las siguientes colecciones estándar implementan las nuevas interfaces:

  • ArrayList, LinkedListSequencedCollection
  • LinkedHashSet, TreeSetSequencedSet
  • LinkedHashMap, TreeMapSequencedMap

Esto significa que, si ya usas estas colecciones, obtienes automáticamente las nuevas capacidades.

2. Métodos principales de SequencedCollection, SequencedSet, SequencedMap

Métodos de SequencedCollection

E getFirst();      // Obtener el primer elemento
E getLast();       // Obtener el último elemento
SequencedCollection<E> reversed(); // Obtener la colección en orden inverso

Métodos de SequencedSet

Los mismos métodos que en SequencedCollection, además de todo lo que hace Set.

Métodos de SequencedMap

Map.Entry<K, V> firstEntry();    // Primer elemento (clave-valor)
Map.Entry<K, V> lastEntry();     // Último elemento (clave-valor)
SequencedMap<K, V> reversed();   // Mapa en orden inverso

3. Ejemplos de uso de las nuevas interfaces

Ejemplo 1: Obtener el primer y el último elemento

import java.util.*;

public class SequencedDemo {
    public static void main(String[] args) {
        SequencedCollection<String> sc = new ArrayList<>();
        sc.add("Java");
        sc.add("Python");
        sc.add("Kotlin");

        // Obtener el primer y el último elemento
        String first = sc.getFirst(); // "Java"
        String last = sc.getLast();   // "Kotlin"

        System.out.println("Primero: " + first);
        System.out.println("Último: " + last);
    }
}

Salida:

Primero: Java
Último: Kotlin

Ejemplo 2: Inversión de la colección

SequencedCollection<String> sc = new LinkedList<>();
sc.add("A");
sc.add("B");
sc.add("C");

SequencedCollection<String> reversed = sc.reversed();
System.out.println(reversed); // [C, B, A]

Ten en cuenta: reversed() devuelve una vista de la colección en orden inverso. Si modificas la colección original, también cambiará la vista reversed.

Ejemplo 3: Trabajo con SequencedSet

SequencedSet<Integer> set = new LinkedHashSet<>();
set.add(100);
set.add(200);
set.add(300);

System.out.println("Primer elemento: " + set.getFirst()); // 100
System.out.println("Último elemento: " + set.getLast()); // 300

SequencedSet<Integer> reversedSet = set.reversed();
System.out.println(reversedSet); // [300, 200, 100]

Ejemplo 4: Trabajo con SequencedMap

SequencedMap<String, Integer> map = new LinkedHashMap<>();
map.put("apple", 5);
map.put("banana", 3);
map.put("cherry", 7);

Map.Entry<String, Integer> first = map.firstEntry();
Map.Entry<String, Integer> last = map.lastEntry();

System.out.println("Primero: " + first.getKey() + " = " + first.getValue()); // apple = 5
System.out.println("Último: " + last.getKey() + " = " + last.getValue()); // cherry = 7

SequencedMap<String, Integer> reversedMap = map.reversed();
System.out.println(reversedMap); // {cherry=7, banana=3, apple=5}

4. ¿Cómo se relaciona esto con tu aplicación?

Supongamos que, en tu aplicación educativa, mantienes una lista de usuarios que han iniciado sesión y quieres obtener rápidamente el primero y el último (por ejemplo, para mostrar «quién entró primero» y «quién lo hizo último»). Antes había que escribir algo como:

List<String> users = new ArrayList<>();
// ... añadimos usuarios
String first = users.get(0);
String last = users.get(users.size() - 1);

Pero si la colección no es una lista sino, por ejemplo, LinkedHashSet (donde los elementos son únicos y se mantiene el orden), ese truco ya no funciona:

Set<String> users = new LinkedHashSet<>();
// ... añadimos usuarios
// ¿Cómo obtener el primero? Solo mediante un iterador:
String first = users.iterator().next();
// ¿Y el último? ¡Solo recorriendo todos los elementos!

Ahora todo es más sencillo y universal:

SequencedSet<String> users = new LinkedHashSet<>();
// ... añadimos usuarios
String first = users.getFirst();
String last = users.getLast();

Esto no solo reduce la cantidad de código, sino que también lo hace más legible y seguro.

5. Esquema de las nuevas interfaces

classDiagram
    Collection <|-- SequencedCollection
    List <|-- SequencedCollection
    Set <|-- SequencedSet
    Map <|-- SequencedMap
    SequencedCollection <|-- SequencedSet
    SequencedSet <|-- LinkedHashSet
    SequencedSet <|-- TreeSet
    SequencedCollection <|-- ArrayList
    SequencedCollection <|-- LinkedList
    SequencedMap <|-- LinkedHashMap
    SequencedMap <|-- TreeMap

6. Matices útiles

Ventajas prácticas de SequencedCollection

  • Interfaz unificada para trabajar con el orden: Ya no hace falta recordar dónde existe get(0), dónde necesitas un iterador y dónde ni siquiera puedes obtener el primer elemento.
  • Comodidad al trabajar con colas y pilas: Es fácil obtener el primer (head) y el último (tail) elemento.
  • Seguridad y legibilidad: Menos errores relacionados con el uso incorrecto de colecciones; el código se vuelve autoexplicativo.
  • Inversión rápida de la colección: El método reversed() permite obtener fácilmente el orden inverso sin manipulaciones manuales.
  • Facilidad de mantenimiento y ampliación del código: Si en el futuro quieres sustituir, por ejemplo, ArrayList por LinkedHashSet, el código que usa SequencedCollection no habrá que reescribirlo.

Particularidades de la implementación

  • No todas las colecciones implementan SequencedCollection: Por ejemplo, HashSet y HashMap no garantizan el orden, por lo que no implementan las nuevas interfaces.
  • Los métodos pueden lanzar excepciones: Si la colección está vacía, llamar a getFirst() o getLast() provocará una NoSuchElementException. No olvides comprobar que la colección no esté vacía.
  • reversed() — es una vista, no una copia: Los cambios en la colección original se reflejan en la vista invertida y viceversa.
  • Compatibilidad: Las nuevas interfaces están disponibles solo a partir de Java 21. Si usas una versión de Java anterior, estas capacidades aún no están disponibles (¡pero es una excelente razón para actualizar!).
  • Genéricos: Todas las nuevas interfaces admiten totalmente genéricos, así que puedes trabajar con cualquier tipo de datos.

7. Errores típicos al trabajar con SequencedCollection

Error n.º 1: esperar soporte de orden en colecciones que no lo garantizan. Si intentas convertir HashSet a SequencedSet, obtendrás un error de compilación — HashSet no tiene orden y no implementa esa interfaz.

Error n.º 2: ignorar colecciones vacías. Llamar a getFirst() o getLast() en una colección vacía lanzará una excepción. Antes de llamar a estos métodos, comprueba que la colección no esté vacía:

if (!sc.isEmpty()) {
    String first = sc.getFirst();
}

Error n.º 3: malentendidos con reversed(). El método reversed() devuelve una vista, no una copia. Si modificas la vista reversed, cambiará también la colección original (y viceversa). Esto puede conducir a resultados inesperados si no cuentas con ese comportamiento.

Error n.º 4: usar las nuevas interfaces en versiones antiguas de Java. Si tu proyecto se compila con una versión inferior a Java 21, el compilador no encontrará estas interfaces. ¡Comprueba la versión del JDK en la configuración del proyecto!

1
Cuestionario/control
Colecciones modernas, nivel 34, lección 4
No disponible
Colecciones modernas
Colecciones modernas e inmutabilidad
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION