W3docs

Introducción al Collections Framework de Java

Un recorrido por el Collections Framework de Java: interfaces, implementaciones y algoritmos en java.util.

Casi todo programa termina almacenando un grupo de cosas — pedidos por enviar, palabras en un documento, usuarios conectados en este momento, la cola de tareas pendientes que procesará un hilo de trabajo. La respuesta de Java a "¿dónde pongo ese grupo?" es el Collections Framework: un conjunto coordinado de interfaces en java.util, más de una docena de implementaciones detrás de ellas, y una única clase de utilidad con algoritmos (Collections) que opera sobre las interfaces en lugar de sobre ninguna implementación concreta. Este capítulo es el mapa — qué contiene el framework, por qué tiene la forma que tiene, y qué familia se usa en qué situación. Cada capítulo de esta parte es un análisis en profundidad de una de las cajas de ese mapa.

Por qué un framework y no solo clases

Antes de Java 1.2 existían clases para grupos (Vector, Hashtable, Stack), pero no había interfaz compartida — no se podía escribir un método que aceptara "cualquier lista" y funcionar con las tres. El Collections Framework solucionó esto separando qué es un grupo (la interfaz) de cómo se almacena (la implementación). El beneficio se ve a diario:

// You program against the interface, not the class.
List<String> names = new ArrayList<>();
// Later, swap in a different implementation without touching the rest of the code:
List<String> names = new LinkedList<>();

Cada método que llamas en names está definido en List. La elección de ArrayList vs. LinkedList es una decisión de rendimiento, no de API. También puedes escribir métodos como void print(List<String> xs) una sola vez y pasar cualquier implementación.

Las cuatro interfaces raíz

El framework se organiza en torno a cuatro interfaces raíz. Elige la que cuyo contrato coincida con tu dato:

  • Collection<E> — la raíz. Un grupo de elementos de tipo E. No se especifica nada sobre orden, duplicados ni indexación.
  • List<E> — una colección ordenada accesible por índice. Se permiten duplicados. Piensa en "array que crece" o "secuencia enlazada." ArrayList, LinkedList, Vector.
  • Set<E> — una colección que prohíbe duplicados. Conjunto matemático. Puede estar ordenado o no. HashSet, LinkedHashSet, TreeSet.
  • Map<K, V> — búsqueda clave→valor. No es una Collection (sus elementos son entradas, no valores simples), pero forma parte del framework. HashMap, LinkedHashMap, TreeMap.

Dos más se sitúan junto a List y Set como especializaciones de Collection:

  • Queue<E> — una colección "siguiente en la fila". FIFO por defecto. LinkedList, ArrayDeque, PriorityQueue.
  • Deque<E> — una cola de doble extremo. Agrega y elimina por cualquiera de los dos extremos. ArrayDeque, LinkedList.

Todas las clases de colección de la biblioteca estándar implementan al menos una de estas interfaces.

Elige la familia por comportamiento, luego la clase por costo

La decisión tiene dos capas:

  1. ¿Qué necesita el dato? Ordenado con duplicados → List. Sin duplicados → Set. Búsqueda por clave → Map. Productor/consumidor → Queue o Deque.
  2. Dentro de la familia, ¿cuáles son los patrones de acceso? Acceso aleatorio por índice → ArrayList. Muchos inserts/removes al frente → LinkedList o ArrayDeque. Iteración ordenada → TreeSet / TreeMap. Solo necesito un contenedor rápido → HashSet / HashMap.

Una hoja de referencia rápida para las clases más usadas:

NecesidadUsaNotas
Lista redimensionable, acceso aleatorio rápidoArrayListEl List predeterminado.
Lista con inserciones/eliminaciones frecuentes en los extremosArrayDeque (como cola similar a lista)Supera a LinkedList en la práctica.
Set, contains/add/remove rápidoHashSetSin garantía de orden.
Set con iteración predecibleLinkedHashSetIteración en orden de inserción.
Set ordenadoTreeSetOperaciones O(log n).
Map, búsqueda rápidaHashMapEl Map predeterminado.
Map con iteración predecibleLinkedHashMapÚtil para cachés (LRU).
Map ordenadoTreeMapClaves en orden.
Cola FIFOArrayDequeMás rápido que LinkedList.
Siempre extraer el mínimoPriorityQueueRespaldado por un heap.

Vector, Stack y Hashtable son las clases anteriores a la versión 1.2 — siguen en el JDK por compatibilidad con versiones anteriores, pero ya no son la elección correcta en código nuevo. Sus reemplazos modernos se cubren en sus propios capítulos.

Los generics hacen que las colecciones sean seguras en tipos

Cada interfaz y clase de colección es genérica. La parametrizas con el tipo de elemento en la declaración, y el compilador lo verifica desde ese momento:

List<String> names = new ArrayList<>();
names.add("Ada");
names.add(42);          // ❌ compile error — Integer is not a String
String first = names.get(0);   // no cast needed

El diamante <> a la derecha le pide al compilador que infiera el tipo a partir de la izquierda — ahorra escritura sin perder seguridad. La parte anterior del libro (Generics) es el reglamento de todo esto; el resto de esta parte asume que ya la leíste.

Los algoritmos viven en la clase Collections

Las operaciones que no están ligadas a ninguna implementación específica — ordenar, mezclar, invertir, búsqueda binaria, mínimo, máximo, frecuencia, envoltorios no modificables — viven en la clase de utilidad estática java.util.Collections. Nótese la s al final: Collection (la interfaz) es un elemento; Collections (la clase) es la caja de herramientas:

List<Integer> xs = new ArrayList<>(List.of(3, 1, 4, 1, 5, 9, 2, 6));
Collections.sort(xs);                    // mutates xs
int idx = Collections.binarySearch(xs, 5);
List<Integer> ro = Collections.unmodifiableList(xs);

Dedicamos tres capítulos al final de esta parte a Collections — búsqueda, ordenación y envoltorios no modificables — porque la clase de utilidad es donde ocurre gran parte del trabajo práctico.

Un primer recorrido completo

El programa siguiente toma un representante de cada familia y muestra las operaciones que usarás una y otra vez. No te preocupes por entender cada línea todavía — cada clase aquí tiene su propio capítulo. El objetivo es ver la forma del framework: los mismos nombres de métodos, los mismos patrones, el mismo modelo de iteración.

java— editable, runs on the server

Observa tres cosas en la salida:

  1. El Set eliminó silenciosamente el duplicado "Effective Java". Ese es el contrato — no se necesita código adicional por tu parte.
  2. La Queue devolvió los elementos en el orden en que se agregaron. offer encola, peek mira la cabeza sin eliminarla, poll la elimina y la devuelve.
  3. El bucle for-each funciona en toda Collection. Los Maps se iteran mediante entrySet(), keySet() o values() según lo que necesites.

Eso es el framework en miniatura.

Advertencia

HashSet y HashMap no garantizan el orden de iteración — el orden que ves en la salida anterior es un detalle de implementación y puede variar entre versiones de la JVM o entre ejecuciones. Si necesitas un orden estable, usa LinkedHashSet/LinkedHashMap (orden de inserción) o TreeSet/TreeMap (orden clasificado). Nunca escribas código que dependa del orden de iteración de un HashSet o HashMap simple.

Qué sigue

Has visto el mapa. El resto de la Parte 11 recorre cada región. El punto de partida natural es la raíz de la que hereda toda colección — la propia interfaz Collection, donde métodos como add, remove, contains, size e iterator() se definen de una vez para siempre.

Práctica

Práctica
Necesitas almacenar un grupo de palabras y responder rápidamente 'está esta palabra en el grupo?' Los duplicados no importan — `cat` o aparece o no aparece. ¿Qué familia del Collections Framework es la más adecuada?
Necesitas almacenar un grupo de palabras y responder rápidamente 'está esta palabra en el grupo?' Los duplicados no importan — `cat` o aparece o no aparece. ¿Qué familia del Collections Framework es la más adecuada?
Was this page helpful?