Java Academy · Lekcja

partitioningBy i counting

Dziel strumień na dwie grupy za pomocą partitioningBy i zliczaj elementy za pomocą counting.

Lekcja 2 z 413 kroki

partitioningBy i counting to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.

Podstawy partitioningBy

Collectors.partitioningBy(predicate) dzieli strumień dokładnie na dwie grupy — true i false — oraz zwraca 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 a filter

W przeciwieństwie do filter partitioningBy zachowuje jednocześnie obie grupy — jest to przydatne, gdy potrzebują Państwo obu części podziału.

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

Kolektor podrzędny z partitioningBy

Połącz partitioningBy z kolektorem podrzędnym tak samo jak 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));

Kolektor counting()

Collectors.counting() zlicza liczbę elementów w strumieniu lub grupie podrzędnej. Jest wygodnym odpowiednikiem 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() jako kolektor podrzędny

counting() szczególnie dobrze sprawdza się jako kolektor podrzędny dla 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

Podział na grupy nazw

Wyodrębnij nazwy z każdej części podziału, używając kolektora podrzędnego 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));

Łączenie counting z summarizingInt

Collectors.summarizingInt() oblicza podczas jednego przejścia liczbę elementów, sumę, minimum, maksimum i średnią:

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

Praktyczny przypadek: podział testu A/B

Podziel użytkowników na grupę kontrolną i badaną na potrzeby testu 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 częstości z groupingBy + counting

Zlicz wystąpienia każdego elementu, tworząc mapę częstości słów:

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 zawsze zwraca oba klucze

W przeciwieństwie do groupingBy partitioningBy zawsze zwraca mapę zawierającą oba klucze true i false — nawet jeśli jedna grupa jest pusta. Zapobiega to wystąpieniu NullPointerException przy wywołaniu 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]

Wydajność: jedno przejście

Zarówno partitioningBy, jak i counting działają podczas jednego przejścia strumienia — O(n). Nie wymagają sortowania. Dzięki temu są znacznie wydajniejsze niż dwukrotne wywołanie filter albo sortowanie przed grupowaniem.

Szybkie sprawdzenie

Jaki jest typ zwracany przez Collectors.partitioningBy(predicate)?

Podsumowanie: partitioningBy i counting

Najważniejsze informacje:

  • partitioningBy dzieli elementy dokładnie na dwie grupy (true/false)
  • Oba klucze są zawsze obecne — w przeciwieństwie do groupingBy nie ma ryzyka NPE
  • counting() zlicza elementy; używaj go jako kolektora podrzędnego dla grup
  • summarizingInt/Long/Double zwraca podczas jednego przejścia liczbę elementów, sumę, minimum, maksimum i średnią
  • Wszystkie te operacje wykonują jedno przejście strumienia o złożoności O(n)
Bezpłatny start

Ucz się Java dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
104
Lekcje
374

Często zadawane pytania

Czy lekcja „partitioningBy i counting” jest bezpłatna?

Tak — pełny tekst „partitioningBy i counting” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „partitioningBy i counting”?

Dziel strumień na dwie grupy za pomocą partitioningBy i zliczaj elementy za pomocą counting. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Java Academy?

Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „partitioningBy i counting”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?

Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. groupingBy: klasyfikowanie elementów
  2. partitioningBy i counting
  3. toMap, joining i summarizing
  4. Tworzenie własnego kolektora
← Powrót do Java Academy