Variantes de Set: LinkedHashSet y TreeSet

Intermedio
Java
Java
Actualizado: 18/04/2026

Tres formas de implementar un conjunto

La interfaz Set<E> garantiza unicidad de elementos (no hay duplicados), pero no especifica cómo se almacenan internamente. El JDK ofrece tres implementaciones principales, cada una con compromisos distintos:

| Clase | Orden | Complejidad básica | |-------|-------|--------------------| | HashSet | Ninguno (según hash) | O(1) operaciones | | LinkedHashSet | Inserción | O(1) operaciones | | TreeSet | Natural o Comparator | O(log n) operaciones |

HashSet: el más rápido, sin orden

HashSet es la implementación por defecto. Usa una tabla hash interna (HashMap por debajo). Ideal cuando solo te importa la pertenencia y el orden es irrelevante.

Set<String> visitados = new HashSet<>();
visitados.add("home");
visitados.add("about");
visitados.add("home"); // ignorado, ya existía
System.out.println(visitados.size()); // 2

Características:

  • No garantiza orden (y el orden puede cambiar entre ejecuciones).
  • Permite un único null.
  • No thread-safe.
  • Complejidad O(1) en add, remove, contains si el hash es bueno.

Usa HashSet cuando: el orden no importa y quieres máxima velocidad.

LinkedHashSet: orden de inserción con costes de HashSet

LinkedHashSet extiende HashSet añadiendo una lista doblemente enlazada que mantiene el orden de inserción. El resultado: misma complejidad O(1), con el extra de preservar orden.

Set<String> orden = new LinkedHashSet<>();
orden.add("tercero");
orden.add("primero");
orden.add("segundo");

for (String s : orden) {
    System.out.println(s); // tercero, primero, segundo
}

Ventajas sobre HashSet:

  • Iteración predecible en el mismo orden que las inserciones.
  • Útil cuando la iteración ordenada importa pero no quieres pagar O(log n) de TreeSet.

Coste ligeramente superior a HashSet en memoria (dos punteros por elemento), pero operaciones siguen siendo O(1).

Implementa SequencedSet (Java 21+)

LinkedHashSet<String> set = new LinkedHashSet<>();
set.add("b");
set.add("c");
set.addFirst("a"); // Java 21+
set.addLast("d");
System.out.println(set); // [a, b, c, d]

String primero = set.getFirst(); // "a"
String ultimo = set.getLast(); // "d"

TreeSet: orden natural o por comparator

TreeSet mantiene los elementos ordenados según el orden natural (Comparable) o un Comparator explícito. Internamente usa un árbol binario balanceado (red-black tree).

Set<Integer> ordenado = new TreeSet<>();
ordenado.add(5);
ordenado.add(1);
ordenado.add(3);
ordenado.add(2);
System.out.println(ordenado); // [1, 2, 3, 5]

// Con Comparator
Set<Persona> porEdad = new TreeSet<>(Comparator.comparingInt(Persona::edad));

Complejidad O(log n) en operaciones: más lento que HashSet pero ofrece:

API NavigableSet

TreeSet implementa NavigableSet (extensión de SortedSet), que aporta métodos utiles:

| Método | Qué hace | |--------|----------| | first() / last() | Menor / mayor | | ceiling(e) | Menor elemento ≥ e | | floor(e) | Mayor elemento ≤ e | | higher(e) | Menor estrictamente > e | | lower(e) | Mayor estrictamente < e | | headSet(e) | Elementos < e | | tailSet(e) | Elementos ≥ e | | subSet(from, to) | Rango [from, to) | | descendingSet() | Vista invertida | | pollFirst() / pollLast() | Extraer y devolver |

NavigableSet<Integer> puntos = new TreeSet<>(List.of(10, 20, 30, 40, 50));
puntos.ceiling(25); // 30 (menor ≥ 25)
puntos.floor(25); // 20 (mayor ≤ 25)
puntos.subSet(20, 40); // [20, 30]
puntos.descendingSet(); // [50, 40, 30, 20, 10]

Ideal para rangos, búsquedas ordenadas, leaderboards, etc.

Null en TreeSet

TreeSet no permite null si usas orden natural (produce NPE al comparar). Con un Comparator explícito, sí podría aceptarlos (dependiendo del comparador).

EnumSet: óptimo para claves enum

Ya visto en el tutorial de enums, pero imprescindible recordar: si tus elementos son de un enum, usa EnumSet:

EnumSet<DayOfWeek> laborales = EnumSet.range(DayOfWeek.MONDAY, DayOfWeek.FRIDAY);
EnumSet<DayOfWeek> finSemana = EnumSet.of(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY);

Es mucho más eficiente que HashSet<DayOfWeek> (bitmap interno).

Thread-safety

Ninguna de estas clases es thread-safe. Alternativas:

  • Collections.synchronizedSet(new HashSet<>()): sincronización externa.
  • ConcurrentHashMap.newKeySet(): set thread-safe basado en ConcurrentHashMap.
  • CopyOnWriteArraySet: para lecturas masivas y pocas modificaciones.

Cómo elegir

| Necesitas... | Usa | |--------------|-----| | Máxima velocidad, orden irrelevante | HashSet | | Preservar orden de inserción | LinkedHashSet | | Orden natural u ordenado por criterio | TreeSet | | Búsquedas por rango o vecinos | TreeSet (NavigableSet) | | Claves de un enum | EnumSet | | Thread-safe, lecturas frecuentes | CopyOnWriteArraySet | | Thread-safe concurrente | ConcurrentHashMap.newKeySet() | | Inmutable (creación literal) | Set.of(...) |

Buenas prácticas

  • El tipo declarado suele ser Set<E> (interfaz); la implementación se elige en la asignación.
  • Iterar HashSet no es reproducible: si lo necesitas, usa LinkedHashSet.
  • TreeSet es más lento pero es la única opción para operaciones ordenadas y de rango.
  • Para datos inmutables pequeños, Set.of(...) es lo más eficiente.
  • Asegúrate de que las clases usadas como elementos tienen equals y hashCode coherentes (o Comparable/Comparator para TreeSet).

Resumen

HashSet, LinkedHashSet y TreeSet cubren tres necesidades distintas: velocidad pura, orden de inserción, y orden por criterio. Conocer sus compromisos permite elegir la estructura correcta sin dejarlo al azar: diferencia clásica entre código que funciona y código bien diseñado.

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

Elegir entre HashSet, LinkedHashSet y TreeSet según la necesidad. Usar LinkedHashSet para preservar orden de inserción con costes HashSet. Aprovechar TreeSet para conjuntos ordenados (API NavigableSet). Entender la complejidad de cada operación. Combinar con SequencedSet (Java 21+). Usar EnumSet para claves enum.