toMap、joining、summarizing
ストリームをマップに変換し、joining で文字列を連結し、summarizingInt で統計値を計算します。
「toMap、joining、summarizing」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
Collectors.toMapの基本
Collectors.toMap(keyMapper, valueMapper)は、ストリームをMapに変換します。各要素から1つのキーと値の組が生成されます。
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重複キーの処理
toMapは、キーが重複するとIllegalStateExceptionをスローします。3番目の引数としてマージ関数を渡すと、競合を解決できます:
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
値マッパーには任意の関数を指定できます。格納する前に要素を変換します:
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.COMtoUnmodifiableMap
Collectors.toUnmodifiableMap()を使用すると、不変Mapを生成できます。これはCollections.unmodifiableMap()でラップするのと同等ですが、より簡潔です:
Map<String, Integer> wordLengths =
Stream.of("Java","Stream","API")
.collect(Collectors.toUnmodifiableMap(w -> w, String::length));
// wordLengths.put("test",4); // throws UnsupportedOperationExceptionCollectors.joining
Collectors.joining()は、文字列要素を連結します。区切り文字、接頭辞、接尾辞をオプションで指定できます:
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]CSV出力のためのjoining
joiningを使用して、CSVの行やSQLのIN句を作成できます:
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()は、1回の走査ですべての統計値を計算し、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.0summingIntとaveragingInt
必要な統計値が1つだけの場合は、より単純な方法を使用できます:
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.0summarizingIntを使用したgroupingBy
グループごとの集計を組み合わせます:
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()));LinkedHashMapへの収集
toMapはデフォルトでHashMap(順序なし)を生成します。4引数版のオーバーロードを使用すると、挿入順を保持するLinkedHashMapを指定できます:
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]実践例: 設定パーサー
toMapを使用して、key=value形式の行をMapに解析します:
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理解度チェック
同じキーを持つ2つの要素を含むストリームに対して、Collectors.toMap(k, v)を使用します。何が起こりますか?
復習: toMap、joining、summarizing
重要なポイント:
- toMap(keyMapper, valueMapper) — マージ関数がない場合、重複キーで例外をスローします
- joining(delimiter, prefix, suffix) — 文字列を効率よく連結します
- summarizingIntは、1回の走査で件数+合計+最小値+最大値+平均値を計算します
- 1つの統計値だけが必要な場合はsummingInt/averagingIntを使用します
- 順序付きの結果には、LinkedHashMap::newを指定した4引数版toMapを使用します
よくある質問
「toMap、joining、summarizing」レッスンは無料ですか?
はい。「toMap、joining、summarizing」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「toMap、joining、summarizing」で何を学びますか?
ストリームをマップに変換し、joining で文字列を連結し、summarizingInt で統計値を計算します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「toMap、joining、summarizing」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- groupingBy:要素の分類
- partitioningBy と counting
- toMap、joining、summarizing
- カスタム Collector の作成