0Pricing
Java Academy · Lección

partitioningBy y counting

Divida un stream en dos grupos con partitioningBy y cuente los elementos con counting.

partitioningBy y counting es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 2 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.

Conceptos básicos de partitioningBy

Collectors.partitioningBy(predicate) divide un stream exactamente en dos grupos: true y false, y devuelve un Map<Boolean, List<T>>.

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

List<Integer> nums = List.of(1,2,3,4,5,6,7,8,9,10);

Map<Boolean, List<Integer>> evenOdd =
    nums.stream().collect(Collectors.partitioningBy(n -> n % 2 == 0));

System.out.println(evenOdd.get(true));  // [2, 4, 6, 8, 10]
System.out.println(evenOdd.get(false)); // [1, 3, 5, 7, 9]

partitioningBy frente a filter

A diferencia de filter, partitioningBy conserva ambos grupos simultáneamente, lo que resulta útil cuando se necesitan las dos partes de la partición.

record Student(String name, int score) {}
List<Student> students = List.of(
    new Student("Alice",90), new Student("Bob",55),
    new Student("Carol",72), new Student("Dave",48)
);

Map<Boolean, List<Student>> result =
    students.stream().collect(
        Collectors.partitioningBy(s -> s.score() >= 60)
    );
System.out.println("Passed: " + result.get(true).size());
System.out.println("Failed: " + result.get(false).size());

Collector downstream con partitioningBy

Combinar partitioningBy con un collector downstream, igual que groupingBy:

Map<Boolean, Long> passFailCount =
    students.stream().collect(
        Collectors.partitioningBy(
            s -> s.score() >= 60,
            Collectors.counting()
        )
    );
System.out.println("Passed: " + passFailCount.get(true));
System.out.println("Failed: " + passFailCount.get(false));

Collector counting()

Collectors.counting() cuenta el número de elementos del stream (o del grupo downstream). Es el equivalente práctico de reducing(0L, e -> 1L, Long::sum).

long count = Stream.of("a","bb","ccc","dddd")
    .collect(Collectors.counting());
System.out.println(count); // 4

// Same as:
long count2 = Stream.of("a","bb","ccc","dddd").count();
// Use counting() as a downstream; use .count() as a terminal op

counting() como downstream

counting() resulta especialmente útil como downstream de groupingBy/partitioningBy:

List<String> words = List.of("cat","dog","car","door","cup","dune");

Map<Character, Long> byFirstLetter =
    words.stream().collect(
        Collectors.groupingBy(w -> w.charAt(0), Collectors.counting())
    );
byFirstLetter.forEach((c, n) -> System.out.println(c + ": " + n));
// c: 3, d: 3

Particionar en nombres

Extraer los nombres de cada partición mediante un collector downstream de mapping:

Map<Boolean, List<String>> namesByPass =
    students.stream().collect(
        Collectors.partitioningBy(
            s -> s.score() >= 60,
            Collectors.mapping(Student::name, Collectors.toList())
        )
    );
System.out.println("Passed: " + namesByPass.get(true));
System.out.println("Failed: " + namesByPass.get(false));

Combinar counting con summarizingInt

Collectors.summarizingInt() calcula el recuento, la suma, el mínimo, el máximo y el promedio en una sola pasada:

IntSummaryStatistics stats =
    students.stream().collect(
        Collectors.summarizingInt(Student::score)
    );
System.out.println("Count: " + stats.getCount());
System.out.println("Average: " + stats.getAverage());
System.out.println("Max: " + stats.getMax());
System.out.println("Min: " + stats.getMin());

Caso de uso real: división para una prueba A/B

Dividir los usuarios en grupos de control y tratamiento para una prueba A/B:

record User(String id, boolean isInTreatment) {}
List<User> users = List.of(
    new User("u1",true), new User("u2",false),
    new User("u3",true), new User("u4",false)
);

Map<Boolean, Long> split =
    users.stream().collect(
        Collectors.partitioningBy(User::isInTreatment, Collectors.counting())
    );
System.out.println("Treatment: " + split.get(true)); // 2
System.out.println("Control: " + split.get(false));  // 2

Mapa de frecuencias con groupingBy + counting

Contar las apariciones de cada elemento (mapa de frecuencia de palabras):

List<String> words2 = List.of("apple","banana","apple","cherry","banana","apple");

Map<String, Long> freq =
    words2.stream().collect(
        Collectors.groupingBy(w -> w, Collectors.counting())
    );
freq.entrySet().stream()
    .sorted(Map.Entry.<String,Long>comparingByValue().reversed())
    .forEach(e -> System.out.println(e.getKey()+": "+e.getValue()));

partitioningBy siempre devuelve ambas claves

A diferencia de groupingBy, partitioningBy siempre devuelve un map con las claves true y false, incluso si uno de los grupos está vacío. Esto evita las NullPointerExceptions al usar map.get(true).

List<Integer> allEven = List.of(2,4,6);
Map<Boolean, List<Integer>> m =
    allEven.stream().collect(Collectors.partitioningBy(n -> n % 2 != 0));
System.out.println(m.get(true));  // [] (empty, not null)
System.out.println(m.get(false)); // [2, 4, 6]

Rendimiento: una sola pasada

Tanto partitioningBy como counting funcionan en una sola pasada del stream: O(n). No requieren ordenar los datos. Por eso son mucho más eficientes que llamar a filter dos veces o que ordenar antes de agrupar.

Comprobación rápida

¿Cuál es el tipo de retorno de Collectors.partitioningBy(predicate)?

Resumen: partitioningBy y counting

Puntos clave:

  • partitioningBy divide los elementos en exactamente dos grupos (true/false)
  • Ambas claves están siempre presentes; no hay riesgo de NPE, a diferencia de groupingBy
  • counting() cuenta los elementos; utilizarlo como downstream de los grupos
  • summarizingInt/Long/Double proporciona recuento+suma+mínimo+máximo+promedio en una sola pasada
  • Todos funcionan en una sola pasada O(n) del stream

Preguntas frecuentes

¿La lección «partitioningBy y counting» es gratis?

Sí — el texto completo de «partitioningBy y counting» 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 «partitioningBy y counting»?

Divida un stream en dos grupos con partitioningBy y cuente los elementos con counting. 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 2 de 4.

¿Cuánto tiempo toma la lección «partitioningBy y counting»?

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