Volver a Java Intermedio

Introducción

Más allá de ArrayList y HashMap, Java proporciona muchos tipos de colecciones especializadas. En este capítulo aprenderás sobre Set, Queue, Deque e implementaciones avanzadas de Map.

Set - Elementos Únicos

Un Set almacena elementos únicos sin duplicados.

import java.util.*; // HashSet - sin orden, más rápido Set<String> hashSet = new HashSet<>(); hashSet.add("Java"); hashSet.add("Kotlin"); hashSet.add("Java"); // Ignorado - duplicado System.out.println(hashSet.size()); // 2 // LinkedHashSet - mantiene orden de inserción Set<String> linkedSet = new LinkedHashSet<>(); linkedSet.add("C"); linkedSet.add("A"); linkedSet.add("B"); // Itera en orden: C, A, B // TreeSet - orden ordenado Set<Integer> treeSet = new TreeSet<>(); treeSet.add(5); treeSet.add(1); treeSet.add(3); // Itera en orden: 1, 3, 5

Queue - Operaciones FIFO

Las colas procesan elementos en orden First-In-First-Out (primero en entrar, primero en salir).

// LinkedList como Queue Queue<String> cola = new LinkedList<>(); cola.offer("Primero"); cola.offer("Segundo"); cola.offer("Tercero"); System.out.println(cola.poll()); // "Primero" System.out.println(cola.peek()); // "Segundo" (no lo elimina) System.out.println(cola.poll()); // "Segundo" // PriorityQueue - ordena por prioridad Queue<Integer> colaPrioridad = new PriorityQueue<>(); colaPrioridad.offer(5); colaPrioridad.offer(1); colaPrioridad.offer(3); System.out.println(colaPrioridad.poll()); // 1 (el menor primero) System.out.println(colaPrioridad.poll()); // 3

Deque - Cola de Doble Extremo

Deque permite agregar/eliminar desde ambos extremos.

Deque<String> deque = new ArrayDeque<>(); // Agregar a ambos extremos deque.addFirst("A"); deque.addLast("C"); deque.addFirst("B"); // Orden: B, A, C // Eliminar desde ambos extremos deque.removeFirst(); // "B" deque.removeLast(); // "C" // Restante: A

LinkedHashMap - Mapa Ordenado

Mantiene el orden de inserción:

Map<String, Integer> linkedMap = new LinkedHashMap<>(); linkedMap.put("Carlos", 30); linkedMap.put("Ana", 25); linkedMap.put("Bob", 28); // Itera en orden de inserción: Carlos, Ana, Bob for (String clave : linkedMap.keySet()) { System.out.println(clave + ": " + linkedMap.get(clave)); }

TreeMap - Mapa Ordenado

Las claves se ordenan automáticamente:

Map<String, Integer> treeMap = new TreeMap<>(); treeMap.put("Carlos", 30); treeMap.put("Ana", 25); treeMap.put("Bob", 28); // Itera en orden alfabético: Ana, Bob, Carlos for (String clave : treeMap.keySet()) { System.out.println(clave + ": " + treeMap.get(clave)); }

Comparación de Rendimiento

ColecciónAgregarContieneIterarOrdenado
HashSetO(1)O(1)O(n)No
LinkedHashSetO(1)O(1)O(n)Inserción
TreeSetO(log n)O(log n)O(n)Ordenado
HashMapO(1)O(1)O(n)No
LinkedHashMapO(1)O(1)O(n)Inserción
TreeMapO(log n)O(log n)O(n)Ordenado

Buenas Prácticas

  • Usa HashSet para búsquedas rápidas sin orden
  • Usa LinkedHashSet cuando el orden de inserción importa
  • Usa TreeSet para ordenamiento automático
  • Usa HashMap para almacenamiento general clave-valor
  • Usa LinkedHashMap para mantener orden de inserción
  • Usa TreeMap para claves ordenadas
  • Elige Queue para procesamiento FIFO
  • Elige Deque para operaciones de pila o doble extremo

Ejemplos Prácticos

Eliminar duplicados de una lista:

List<String> listaConDuplicados = Arrays.asList("A", "B", "A", "C", "B"); Set<String> conjuntoUnico = new HashSet<>(listaConDuplicados); List<String> listaUnica = new ArrayList<>(conjuntoUnico);

Programación de tareas con prioridad:

Queue<Tarea> colaTareas = new PriorityQueue<>( Comparator.comparingInt(Tarea::getPrioridad) ); colaTareas.offer(new Tarea("Prioridad baja", 3)); colaTareas.offer(new Tarea("Prioridad alta", 1)); colaTareas.offer(new Tarea("Prioridad media", 2)); while (!colaTareas.isEmpty()) { Tarea tarea = colaTareas.poll(); tarea.ejecutar(); }

Caché LRU con LinkedHashMap:

public class CacheLRU<K, V> extends LinkedHashMap<K, V> { private final int capacidad; public CacheLRU(int capacidad) { super(capacidad, 0.75f, true); // accessOrder = true this.capacidad = capacidad; } @Override protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > capacidad; } }

Conclusión

Comprender diferentes tipos de colecciones y sus características de rendimiento te ayuda a elegir la estructura de datos correcta para cada situación, conduciendo a un código más eficiente.

En el próximo capítulo, exploraremos Streams y expresiones Lambda.