Java Academy · レッスン

groupingBy:要素の分類

分類関数でストリーム要素をマップのグループにまとめ、下流の Collector と組み合わせます。

レッスン 1/413 ステップ

「groupingBy:要素の分類」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

groupingByとは

Collectors.groupingBy()は、ストリームの要素を、各キーが一致する要素のリストに対応するMapへ分類します。これはSQLのGROUP BYに相当するストリーム操作です。

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

下流コレクター: counting

groupingByと下流コレクターを組み合わせると、要素を一覧化する代わりに集計できます:

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

下流コレクター: mapping

Collectors.mapping()を下流コレクターとして使用すると、収集する前に要素を変換できます:

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

下流コレクター: joining

グループごとの名前を、カンマ区切りの1つの文字列に連結します:

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

groupingByの呼び出しを入れ子にすると、多次元の分類ができます:

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

Map型の制御

groupingByはデフォルトでHashMapを生成します。3引数版のオーバーロードを使用すると、キーをソートするTreeMapなど、別のMap型を指定できます:

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

下流コレクター: averagingInt

グループごとの平均値を計算します:

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

下流コレクター: toUnmodifiableList

下流コレクターにCollectors.toUnmodifiableList()を使用すると、不変のグループを生成できます:

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

実践例: 注文の概要

注文をステータス別にグループ化し、グループごとに金額を合計します:

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

パフォーマンスに関する考慮事項

groupingByはすべての要素をメモリに収集します。非常に大規模なデータセットでは、チャンク単位で処理するか、データベースレベルのGROUP BYを使用することを検討してください。下流コレクターは要素ごとに実行されるため、O(n²)の動作を避けるために軽量に保ちます。

filterおよびsortedとの組み合わせ

収集する前にストリーム操作を連結すると、データを事前にフィルタリングまたはソートできます:

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}

理解度チェック

Collectors.groupingBy(Person::city)をcollect()とともに使用した場合、どの型が生成されますか?

復習: groupingBy

重要なポイント:

  • groupingBy(classifier) → Map<K, List<T>>
  • counting、mapping、joining、summarizingなどの下流コレクターと組み合わせられます
  • groupingByを入れ子にして多次元の分類ができます
  • 3引数版のオーバーロードを使用して、結果のMap型(例: TreeMap)を制御できます
無料で開始

AI チューターと学ぶ Java — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
104
レッスン
374

よくある質問

「groupingBy:要素の分類」レッスンは無料ですか?

はい。「groupingBy:要素の分類」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「groupingBy:要素の分類」で何を学びますか?

分類関数でストリーム要素をマップのグループにまとめ、下流の Collector と組み合わせます。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「groupingBy:要素の分類」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. groupingBy:要素の分類
  2. partitioningBy と counting
  3. toMap、joining、summarizing
  4. カスタム Collector の作成
← Java Academyに戻る