Interfaz Collection en Java
La interfaz raíz Collection en Java y el contrato que heredan cada lista, conjunto y cola.
java.util.Collection<E> es la raíz de la parte del framework que almacena elementos individuales — cada List, Set, Queue y Deque la implementa (la única familia que no lo hace es Map, cuyos elementos son entradas, no valores individuales). Todo lo que puedes hacer "sin importar qué grupo sea" — agregar, eliminar, preguntar contains, iterar, contar, convertir a array, hacer streaming — está declarado aquí. Este capítulo es el contrato: los métodos en los que puedes confiar para cualquier colección, los pocos que pueden lanzar excepciones, y el modelo de iteración que hereda cada implementación.
La jerarquía de un vistazo
Iterable<E>
└── Collection<E>
├── List<E> — ordered, indexed, duplicates allowed
├── Set<E> — no duplicates
│ └── SortedSet<E> → NavigableSet<E>
└── Queue<E> — "next in line"
└── Deque<E> — double-ended queueCollection extiende Iterable<E>, razón por la que cada colección funciona con el bucle for-each. Las dos especializaciones de Collection — Set y Queue — refinan el contrato; Map tiene su propia raíz.
Métodos principales que tiene toda colección
A continuación se presenta el conjunto completo de métodos de instancia en Collection, agrupados por propósito. Memoriza las categorías en lugar de la lista — una vez que sabes que existe un método llamado removeIf, puedes encontrarlo.
Tamaño y vacuidad
int size()— número de elementos.boolean isEmpty()—size() == 0pero a menudo más rápido.
Agregar
boolean add(E e)— agrega un elemento. Devuelvetruesi la colección cambió. (UnSetdevuelvefalsepara un duplicado.)boolean addAll(Collection<? extends E> c)— agrega cada elemento dec.
Eliminar
boolean remove(Object o)— elimina una ocurrencia deo.boolean removeAll(Collection<?> c)— elimina cada elemento que aparece enc.boolean retainAll(Collection<?> c)— conserva solo los elementos enc(intersección).boolean removeIf(Predicate<? super E> filter)— elimina cada elemento que coincide con el predicado. La forma más limpia de filtrar en el lugar.void clear()— vacía la colección.
Consultar
boolean contains(Object o)— prueba de pertenencia.boolean containsAll(Collection<?> c)— prueba de subconjunto.
Iteración y vistas masivas
Iterator<E> iterator()— el iterador subyacente; lo que usafor-each.Stream<E> stream()/parallelStream()— abre unStreamsobre los elementos.void forEach(Consumer<? super E> action)— heredado deIterable. La forma funcional de iteración.
Conversión a array
Object[] toArray()<T> T[] toArray(T[] a)y el más nuevo<T> T[] toArray(IntFunction<T[]> generator)(Java 11+) — array tipado.
Esa es la interfaz completa. Cada lista, conjunto y cola que encontrarás en esta parte es simplemente una implementación diferente de esos métodos más algunos propios.
Igualdad y equals / hashCode
Collection.equals(Object) no está definido en la raíz — cada sub-interfaz especifica qué significa la igualdad para ella. List requiere los mismos elementos en el mismo orden; Set requiere los mismos elementos independientemente del orden; Queue no define equals en absoluto (una cola LinkedList y una cola ArrayDeque con el mismo contenido no son iguales porque la comparación recurre a la identidad). No compares colecciones entre familias y esperes simetría.
Los elementos almacenados en una Collection deben tener equals / hashCode coherentes si quieres que contains, remove y (para colecciones basadas en hash) las búsquedas funcionen correctamente. Cubrimos el contrato en el capítulo de equals y hashCode — ese es el prerrequisito para usar Set y Map con tus propias clases.
Operaciones opcionales
Algunas colecciones son no modificables — List.of(1,2,3), Collections.unmodifiableList(list), las vistas devueltas por Map.keySet() en ciertas implementaciones, etc. Aún así implementan Collection, pero llamar a add, remove, clear, o cualquier método mutante lanza UnsupportedOperationException. El Javadoc llama a estas "operaciones opcionales." Es lo más cercano que tiene Java a un rechazo en tiempo de ejecución de partes de una interfaz; el precio es que el compilador no puede detectar el error — lo descubres en el primer lanzamiento.
Una regla segura: si no construiste la colección, trátala como posiblemente no modificable. Si necesitas una copia mutable, haz new ArrayList<>(received) primero.
Iteración: tres formas, un mecanismo subyacente
Cada colección admite tres estilos de iteración, y los tres terminan llamando a iterator():
Collection<String> names = List.of("Ada", "Linus", "Grace");
// 1. for-each — the everyday form
for (String n : names) System.out.println(n);
// 2. forEach with a lambda — declarative
names.forEach(System.out::println);
// 3. Iterator — when you need to remove during iteration
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.startsWith("L")) it.remove(); // safe; for-each can't do this
}Por qué las formas 1 y 3 siguen siendo importantes: el bucle for-each no puede modificar la colección subyacente sin lanzar ConcurrentModificationException. Cuando necesitas eliminar mientras iteras, recurres al Iterator explícito. El capítulo de Iteradores más adelante en esta parte cubre el protocolo en detalle.
Álgebra de conjuntos con operaciones masivas
Las operaciones masivas convierten una colección en una calculadora de álgebra de conjuntos (independientemente de si es un Set — también funcionan en List):
Collection<Integer> a = new ArrayList<>(List.of(1, 2, 3, 4));
Collection<Integer> b = List.of(3, 4, 5);
a.addAll(b); // union (multiset)
a.retainAll(List.of(3, 4)); // intersection
a.removeAll(List.of(3)); // differenceEstas son la forma segura y sin dependencias de expresar "conservar solo los elementos que también están en b" sin escribir un bucle. Modifican el receptor — si necesitas un resultado inmutable, copia primero.
Un ejemplo completo: cada método, uno al lado del otro
El programa a continuación ejercita cada categoría de método de Collection con el mismo ArrayList, para que puedas verlos en un solo lugar y observar el contrato en acción.
Dos cosas que vale la pena destacar de la salida:
remove("red")solo eliminó la primera ocurrencia — ese es el contrato enCollection. Para eliminar todas las coincidencias, usaremoveIf(lo viste a continuación, eliminando cada palabra de más de cuatro caracteres).- La
UnsupportedOperationExceptiondefrozen.add("d")es la regla de "operaciones opcionales" en acción.frozenimplementaCollection, por lo que la llamada compila. La implementación eligió no soportarla, y lo descubres en tiempo de ejecución.
Qué sigue
Collection es el contrato abstracto. El primer refinamiento concreto que encontrarás es el que agrega orden e indexación — la interfaz List. Ahí es donde entran en escena el acceso indexado, las sublistas y las operaciones que preservan el orden.