0Pricing
Java Academy · Lección

groupingBy: clasificación de elementos

Agrupe elementos de un stream en mapas mediante una función clasificadora y combínelos con collectors posteriores.

groupingBy: clasificación de elementos es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.

¿Qué es groupingBy?

Collectors.groupingBy() divide los elementos de un stream en un Map, donde cada clave se asocia a una lista de elementos coincidentes. Es el equivalente de GROUP BY de SQL para streams.

import java.util.*;
import java.util.stream.*;

record Person(String name, String city) {}
List<Person> people = List.of(
    new Person("Alice","NYC"), new Person("Bob","LA"),
    new Person("Carol","NYC"), new Person("Dave","LA"),
    new Person("Eve","Chicago")
);

Map<String, List<Person>> byCity =
    people.stream().collect(Collectors.groupingBy(Person::city));
byCity.forEach((city, ps) -> System.out.println(city + ": " + ps.size()));

Collector downstream: counting

Combinar groupingBy con un collector downstream para realizar una agregación en lugar de crear una lista:

Map<String, Long> countByCity =
    people.stream().collect(
        Collectors.groupingBy(Person::city, Collectors.counting())
    );
countByCity.forEach((city, n) -> System.out.println(city + " -> " + n));
// NYC -> 2, LA -> 2, Chicago -> 1

Collector downstream: mapping

Usar Collectors.mapping() como collector downstream para transformar los elementos antes de recopilarlos:

Map<String, List<String>> namesByCity =
    people.stream().collect(
        Collectors.groupingBy(
            Person::city,
            Collectors.mapping(Person::name, Collectors.toList())
        )
    );
namesByCity.forEach((city, names) -> System.out.println(city + ": " + names));

Collector downstream: joining

Concatenar los nombres de cada grupo en una sola cadena separada por comas:

Map<String, String> joinedByCity =
    people.stream().collect(
        Collectors.groupingBy(
            Person::city,
            Collectors.mapping(Person::name, Collectors.joining(", "))
        )
    );
joinedByCity.forEach((city, s) -> System.out.println(city + ": " + s));
// NYC: Alice, Carol

groupingBy multinivel

Anidar llamadas a groupingBy para realizar una clasificación multidimensional:

record Employee(String name, String dept, String level) {}
List<Employee> emps = List.of(
    new Employee("A","Eng","Junior"), new Employee("B","Eng","Senior"),
    new Employee("C","HR","Junior"), new Employee("D","HR","Senior")
);

Map<String, Map<String, List<Employee>>> grouped =
    emps.stream().collect(
        Collectors.groupingBy(Employee::dept,
            Collectors.groupingBy(Employee::level))
    );
grouped.forEach((dept, levels) -> levels.forEach((level, list) ->
    System.out.println(dept+"/"+level+": "+list.size())));

Control del tipo de Map

De forma predeterminada, groupingBy produce un HashMap. Usar la sobrecarga de 3 argumentos para especificar otro tipo de map, como TreeMap para obtener claves ordenadas:

Map<String, Long> sorted =
    people.stream().collect(
        Collectors.groupingBy(Person::city, TreeMap::new, Collectors.counting())
    );
System.out.println(sorted); // keys in alphabetical order

Downstream: averagingInt

Calcular promedios por grupo:

record Product(String category, int price) {}
List<Product> products = List.of(
    new Product("A",10), new Product("A",20),
    new Product("B",15), new Product("B",25)
);

Map<String, Double> avgPrice =
    products.stream().collect(
        Collectors.groupingBy(Product::category,
            Collectors.averagingInt(Product::price))
    );
avgPrice.forEach((cat, avg) -> System.out.printf("%s: %.1f%n", cat, avg));

Downstream: toUnmodifiableList

Usar Collectors.toUnmodifiableList() como collector downstream para producir grupos inmutables:

Map<String, List<String>> immutable =
    people.stream().collect(
        Collectors.groupingBy(Person::city,
            Collectors.mapping(Person::name, Collectors.toUnmodifiableList()))
    );
// Attempting to modify throws UnsupportedOperationException

Caso de uso real: resumen de pedidos

Agrupar los pedidos por estado y sumar los importes de cada grupo:

record Order(String status, double amount) {}
List<Order> orders = List.of(
    new Order("PAID", 50.0), new Order("PENDING", 30.0),
    new Order("PAID", 75.0), new Order("CANCELLED", 20.0)
);

Map<String, Double> totalByStatus =
    orders.stream().collect(
        Collectors.groupingBy(Order::status,
            Collectors.summingDouble(Order::amount))
    );
totalByStatus.forEach((s, t) -> System.out.printf("%s: $%.2f%n", s, t));

Consideraciones de rendimiento

groupingBy almacena todos los elementos en memoria. Para conjuntos de datos muy grandes, considerar procesarlos por bloques o usar un GROUP BY en el nivel de la base de datos. El collector downstream se ejecuta para cada elemento; mantenerlo ligero para evitar un comportamiento O(n²).

Combinar con filter y sorted

Encadenar operaciones de stream antes de recopilar los datos para filtrarlos u ordenarlos previamente:

Map<String, Long> activeCities =
    people.stream()
          .filter(p -> !p.city().equals("Chicago"))
          .collect(Collectors.groupingBy(Person::city, Collectors.counting()));
System.out.println(activeCities); // {NYC=2, LA=2}

Comprobación rápida

¿Qué tipo produce Collectors.groupingBy(Person::city) cuando se utiliza con collect()?

Resumen: groupingBy

Puntos clave:

  • groupingBy(classifier) → Map<K, List<T>>
  • Combinar con collectors downstream: counting, mapping, joining, summarizing
  • Anidar groupingBy para realizar una clasificación multidimensional
  • Usar la sobrecarga de 3 argumentos para controlar el tipo de map resultante (por ejemplo, TreeMap)

Preguntas frecuentes

¿La lección «groupingBy: clasificación de elementos» es gratis?

Sí — el texto completo de «groupingBy: clasificación de elementos» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.

¿Qué aprenderé en «groupingBy: clasificación de elementos»?

Agrupe elementos de un stream en mapas mediante una función clasificadora y combínelos con collectors posteriores. Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Java Academy?

No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.

¿Cuánto tiempo toma la lección «groupingBy: clasificación de elementos»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Java Academy?

Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. groupingBy: clasificación de elementos
  2. partitioningBy y counting
  3. toMap, joining y summarizing
  4. Creación de un Collector personalizado
← Volver a Java Academy