Operaciones finales con Streams: collect()

Intermedio
Java
Java
Actualizado: 08/05/2025

¡Desbloquea el curso completo!

IA
Ejercicios
Certificado
Entrar

collect(), toList(), toSet(), toMap()

La operación terminal collect() es una de las herramientas más versátiles en el API Stream de Java, permitiendo transformar los elementos de un stream en diferentes tipos de colecciones o valores. Esta operación funciona en conjunto con la interfaz Collector, que define cómo se acumularán los elementos procesados.

¿Te está gustando esta lección?

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

La sintaxis básica de collect() es:

<R, A> R collect(Collector<? super T, A, R> collector)

Donde:

  • T es el tipo de elementos en el stream
  • R es el tipo del resultado
  • A es el tipo del acumulador intermedio

La clase Collectors proporciona implementaciones predefinidas que facilitan las operaciones más comunes. Veamos los colectores fundamentales:

Collector toList()

El método toList() convierte los elementos de un stream en una lista:

import java.util.List;
import java.util.stream.Collectors;

public class EjemploToList {
    public static void main(String[] args) {
        List<String> nombres = List.of("Ana", "Carlos", "Beatriz", "Daniel");
        
        // Filtrar nombres que empiezan con 'A' o 'B' y convertirlos a lista
        List<String> filtrados = nombres.stream()
                                        .filter(n -> n.startsWith("A") || n.startsWith("B"))
                                        .collect(Collectors.toList());
        
        System.out.println("Nombres filtrados: " + filtrados);
    }
}

Este código produce una lista con los elementos "Ana" y "Beatriz". A partir de Java 16, también podemos usar el método toList() directamente en el Stream:

List<String> filtrados = nombres.stream()
                               .filter(n -> n.startsWith("A") || n.startsWith("B"))
                               .toList(); // Método directo desde Java 16

La diferencia principal es que el método directo toList() devuelve una lista inmutable, mientras que Collectors.toList() devuelve una lista modificable.

Collector toSet()

El método toSet() convierte los elementos de un stream en un conjunto (Set), eliminando automáticamente los duplicados:

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class EjemploToSet {
    public static void main(String[] args) {
        List<String> palabras = List.of("Java", "Python", "Java", "JavaScript", "Python");
        
        // Convertir a Set para eliminar duplicados
        Set<String> lenguajesUnicos = palabras.stream()
                                             .collect(Collectors.toSet());
        
        System.out.println("Lenguajes únicos: " + lenguajesUnicos);
    }
}

Este código produce un conjunto con los elementos "Java", "Python" y "JavaScript", eliminando los duplicados.

Collector toMap()

El método toMap() permite convertir los elementos de un stream en un mapa, especificando cómo extraer las claves y los valores:

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

class Producto {
    private String nombre;
    private double precio;
    
    public Producto(String nombre, double precio) {
        this.nombre = nombre;
        this.precio = precio;
    }
    
    public String getNombre() { return nombre; }
    public double getPrecio() { return precio; }
}

public class EjemploToMap {
    public static void main(String[] args) {
        List<Producto> productos = List.of(
            new Producto("Laptop", 1200.0),
            new Producto("Teléfono", 800.0),
            new Producto("Tablet", 500.0)
        );
        
        // Crear un mapa con nombre como clave y precio como valor
        Map<String, Double> preciosPorProducto = productos.stream()
            .collect(Collectors.toMap(
                Producto::getNombre,  // función para extraer la clave
                Producto::getPrecio   // función para extraer el valor
            ));
        
        System.out.println("Precios por producto: " + preciosPorProducto);
    }
}

Este código crea un mapa donde las claves son los nombres de los productos y los valores son sus precios.

Si existe la posibilidad de claves duplicadas, podemos proporcionar una función de resolución de conflictos:

Map<String, Double> preciosPorProducto = productos.stream()
    .collect(Collectors.toMap(
        Producto::getNombre,
        Producto::getPrecio,
        (precioExistente, precioNuevo) -> precioNuevo  // En caso de duplicados, usar el nuevo valor
    ));

Otros colectores útiles

Además de los colectores básicos, Collectors ofrece métodos para realizar operaciones de agregación:

joining(): Concatena elementos de tipo String:

List<String> frutas = List.of("Manzana", "Banana", "Cereza");
String resultado = frutas.stream()
                        .collect(Collectors.joining(", "));
System.out.println("Frutas: " + resultado);  // Imprime: Frutas: Manzana, Banana, Cereza

summingInt(), summingLong(), summingDouble(): Suman valores numéricos:

List<Producto> productos = List.of(
    new Producto("Laptop", 1200.0),
    new Producto("Teléfono", 800.0),
    new Producto("Tablet", 500.0)
);

double precioTotal = productos.stream()
                             .collect(Collectors.summingDouble(Producto::getPrecio));
System.out.println("Precio total: " + precioTotal);  // Imprime: Precio total: 2500.0

averagingInt(), averagingLong(), averagingDouble(): Calculan promedios:

double precioPromedio = productos.stream()
                                .collect(Collectors.averagingDouble(Producto::getPrecio));
System.out.println("Precio promedio: " + precioPromedio);  // Imprime: Precio promedio: 833.3333...

counting(): Cuenta elementos:

long cantidad = productos.stream()
                        .collect(Collectors.counting());
System.out.println("Cantidad de productos: " + cantidad);  // Imprime: Cantidad de productos: 3

maxBy(), minBy(): Encuentran el máximo o mínimo según un comparador:

import java.util.Comparator;
import java.util.Optional;

Optional<Producto> masBarato = productos.stream()
    .collect(Collectors.minBy(Comparator.comparing(Producto::getPrecio)));

masBarato.ifPresent(p -> System.out.println("Producto más barato: " + p.getNombre()));

Colectores personalizados

También podemos crear colectores personalizados utilizando el método Collectors.collectingAndThen(), que permite aplicar una función final al resultado de otro colector:

List<Integer> numeros = List.of(1, 2, 3, 4, 5);

// Colectar a lista y convertir a array inmutable
Integer[] arrayNumeros = numeros.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.toList(),
        lista -> lista.toArray(new Integer[0])
    ));

La operación collect() junto con los colectores predefinidos proporciona una forma elegante y funcional de transformar streams en estructuras de datos útiles. Estos colectores simplifican operaciones que de otro modo requerirían código imperativo más extenso y propenso a errores.

Aprendizajes de esta lección

  • Comprender la función y sintaxis de la operación terminal collect() en Streams.
  • Utilizar colectores predefinidos como toList(), toSet() y toMap() para transformar streams en colecciones.
  • Aplicar colectores para realizar operaciones de agregación como sumas, promedios y conteos.
  • Crear y usar colectores personalizados con collectingAndThen() para transformar resultados.
  • Diferenciar entre listas mutables e inmutables generadas por diferentes métodos de colectores.

Completa Java y certifícate

Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración