0Pricing
Java Academy · Lezione

partitioningBy e counting

Divida uno stream in due gruppi con partitioningBy e conti gli elementi con counting.

partitioningBy e counting è una lezione Java Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Java Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Java Academy include 4 lezioni in totale.

Nozioni di base su partitioningBy

Collectors.partitioningBy(predicate) divide uno stream in esattamente due gruppi: true e false; restituisce una 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 e filter a confronto

A differenza di filter, partitioningBy conserva simultaneamente entrambi i gruppi: è utile quando servono entrambe le parti della suddivisione.

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());

Downstream con partitioningBy

Combini partitioningBy con un collector downstream proprio come 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() conta il numero di elementi nello stream o nel gruppo downstream. È l'equivalente pratico di 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() come downstream

counting() è particolarmente utile come downstream per 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

Suddivisione in base ai nomi

Estragga i nomi da ogni partizione utilizzando un mapping downstream:

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));

Combinazione di counting e summarizingInt

Collectors.summarizingInt() calcola conteggio, somma, minimo, massimo e media in un'unica passata:

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 d'uso reale: suddivisione di un test A/B

Divida gli utenti in gruppi di controllo e trattamento per un test 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

Mappa delle frequenze con groupingBy + counting

Conti le occorrenze di ogni elemento, creando una mappa delle frequenze delle parole:

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 restituisce sempre entrambe le chiavi

A differenza di groupingBy, partitioningBy restituisce sempre una map con entrambe le chiavi true e false, anche se uno dei gruppi è vuoto. In questo modo si evitano NullPointerExceptions su 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]

Prestazioni: passata singola

Sia partitioningBy sia counting operano in un'unica passata sullo stream: O(n). Non richiedono l'ordinamento. Per questo sono molto più efficienti rispetto a chiamare filter due volte o a ordinare prima del raggruppamento.

Verifica rapida

Qual è il tipo restituito da Collectors.partitioningBy(predicate)?

Riepilogo: partitioningBy e counting

Punti chiave:

  • partitioningBy divide gli elementi in esattamente due gruppi, true/false
  • Entrambe le chiavi sono sempre presenti: nessun rischio di NPE, a differenza di groupingBy
  • counting() conta gli elementi; lo utilizzi come downstream per i gruppi
  • summarizingInt/Long/Double fornisce conteggio, somma, minimo, massimo e media in un'unica passata
  • Tutte queste operazioni vengono eseguite in un'unica passata O(n) sullo stream

Domande Frequenti

La lezione «partitioningBy e counting» è gratuita?

Sì — il testo completo di «partitioningBy e counting» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Java Academy, passa a CoddyKit PRO. Il corso Java Academy include 4 lezioni in totale.

Cosa imparerò in «partitioningBy e counting»?

Divida uno stream in due gruppi con partitioningBy e conti gli elementi con counting. Eserciti Java Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Java Academy?

Non è richiesta alcuna esperienza precedente. Java Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «partitioningBy e counting»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Java Academy?

Sì. Ogni lezione Java Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. groupingBy: classificare gli elementi
  2. partitioningBy e counting
  3. toMap, joining e summarizing
  4. Creazione di un Collector personalizzato
← Torna a Java Academy