0Pricing
Java Academy · Lekcja

toMap, joining i summarizing

Konwertuj strumienie na mapy, łącz łańcuchy znaków za pomocą joining i obliczaj statystyki przez summarizingInt.

toMap, joining i summarizing to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 3 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 Collectors.toMap

Collectors.toMap(keyMapper, valueMapper) przekształca strumień w obiekt Map. Każdy element dostarcza jedną parę klucz-wartość.

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

record Country(String code, String name) {}
List<Country> countries = List.of(
    new Country("US","United States"),
    new Country("DE","Germany"),
    new Country("JP","Japan")
);

Map<String, String> codeToName =
    countries.stream().collect(
        Collectors.toMap(Country::code, Country::name)
    );
System.out.println(codeToName.get("DE")); // Germany

Obsługa zduplikowanych kluczy

toMap zgłasza IllegalStateException w przypadku zduplikowanych kluczy. Przekaż funkcję scalającą jako trzeci argument, aby rozwiązać konflikty:

List<String> words = List.of("apple","ant","banana","bat","cherry");

Map<Character, String> firstByLetter =
    words.stream().collect(
        Collectors.toMap(
            w -> w.charAt(0),
            w -> w,
            (existing, replacement) -> existing // keep first
        )
    );
System.out.println(firstByLetter); // {a=apple, b=banana, c=cherry}

toMap z przekształcaniem wartości

Mapper wartości może być dowolną funkcją — przekształć element przed zapisaniem:

record User(String login, String email) {}
List<User> users = List.of(
    new User("alice","alice@example.com"),
    new User("bob","bob@example.com")
);

Map<String, String> loginToEmail =
    users.stream().collect(
        Collectors.toMap(User::login, u -> u.email().toUpperCase())
    );
System.out.println(loginToEmail.get("alice")); // ALICE@EXAMPLE.COM

toUnmodifiableMap

Użyj Collectors.toUnmodifiableMap(), aby utworzyć niezmienną mapę — jest to odpowiednik opakowania za pomocą Collections.unmodifiableMap(), ale w bardziej przejrzystej formie:

Map<String, Integer> wordLengths =
    Stream.of("Java","Stream","API")
          .collect(Collectors.toUnmodifiableMap(w -> w, String::length));
// wordLengths.put("test",4); // throws UnsupportedOperationException

Collectors.joining

Collectors.joining() łączy elementy typu string. Przyjmuje opcjonalny separator, prefiks i sufiks:

List<String> names = List.of("Alice","Bob","Carol");

System.out.println(names.stream().collect(Collectors.joining()));
// AliceBobCarol

System.out.println(names.stream().collect(Collectors.joining(", ")));
// Alice, Bob, Carol

System.out.println(names.stream().collect(Collectors.joining(", ", "[", "]")));
// [Alice, Bob, Carol]

joining do generowania danych CSV

Twórz wiersze CSV lub klauzule SQL IN za pomocą joining:

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

String inClause = ids.stream()
    .map(Object::toString)
    .collect(Collectors.joining(",", "(", ")"));
System.out.println("WHERE id IN " + inClause);
// WHERE id IN (1,2,3,4,5)

summarizingInt / Long / Double

Collectors.summarizingInt() oblicza wszystkie statystyki podczas jednego przejścia i zwraca obiekt IntSummaryStatistics:

record Product(String name, int price) {}
List<Product> products = List.of(
    new Product("A",100), new Product("B",200), new Product("C",150)
);

IntSummaryStatistics stats =
    products.stream().collect(Collectors.summarizingInt(Product::price));

System.out.println("Count: " + stats.getCount());   // 3
System.out.println("Sum: "   + stats.getSum());     // 450
System.out.println("Min: "   + stats.getMin());     // 100
System.out.println("Max: "   + stats.getMax());     // 200
System.out.println("Avg: "   + stats.getAverage()); // 150.0

summingInt i averagingInt

W prostszych przypadkach, gdy potrzebna jest tylko jedna statystyka:

int total = products.stream().collect(Collectors.summingInt(Product::price));
System.out.println("Total: " + total); // 450

double avg = products.stream().collect(Collectors.averagingInt(Product::price));
System.out.println("Average: " + avg); // 150.0

groupingBy z summarizingInt

Połącz agregowanie statystyk dla poszczególnych grup:

record Sale(String region, int amount) {}
List<Sale> sales = List.of(
    new Sale("North",100), new Sale("South",200),
    new Sale("North",150), new Sale("South",300)
);

Map<String, IntSummaryStatistics> statsByRegion =
    sales.stream().collect(
        Collectors.groupingBy(Sale::region,
            Collectors.summarizingInt(Sale::amount))
    );
statsByRegion.forEach((r,s) ->
    System.out.printf("%s: sum=%d avg=%.1f%n", r, s.getSum(), s.getAverage()));

Zbieranie do LinkedHashMap

Domyślnie toMap tworzy HashMap, która nie zachowuje kolejności. Użyj przeciążenia z czterema argumentami, aby określić LinkedHashMap i zachować kolejność wstawiania:

Map<String, Integer> ordered =
    Stream.of("banana","apple","cherry")
          .collect(Collectors.toMap(
              w -> w,
              String::length,
              (a,b) -> a,
              LinkedHashMap::new
          ));
System.out.println(ordered.keySet()); // [banana, apple, cherry]

Praktyczny przypadek: parser konfiguracji

Przeanalizuj wiersze w formacie key=value i zapisz je w mapie za pomocą toMap:

List<String> lines = List.of("host=localhost","port=5432","db=myapp");

Map<String, String> config =
    lines.stream()
         .map(l -> l.split("=", 2))
         .collect(Collectors.toMap(a -> a[0], a -> a[1]));

System.out.println(config.get("port")); // 5432

Szybkie sprawdzenie

Używają Państwo Collectors.toMap(k, v) dla strumienia zawierającego dwa elementy z tym samym kluczem. Co się stanie?

Podsumowanie: toMap, joining, summarizing

Najważniejsze informacje:

  • toMap(keyMapper, valueMapper) — bez funkcji scalającej zgłasza wyjątek dla zduplikowanych kluczy
  • joining(delimiter, prefix, suffix) — elegancko łączy ciągi znaków
  • summarizingInt zwraca podczas jednego przejścia liczbę elementów, sumę, minimum, maksimum i średnią
  • summingInt/averagingInt służą do obliczania pojedynczej statystyki
  • Użyj toMap z czterema argumentami i LinkedHashMap::new, aby uzyskać uporządkowane wyniki

Często zadawane pytania

Czy lekcja „toMap, joining i summarizing” jest bezpłatna?

Tak — pełny tekst „toMap, joining i summarizing” 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 „toMap, joining i summarizing”?

Konwertuj strumienie na mapy, łącz łańcuchy znaków za pomocą joining i obliczaj statystyki przez summarizingInt. Ć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 3 z 4.

Ile czasu zajmuje lekcja „toMap, joining i summarizing”?

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