4. Collectorsクラス(46-65)
Java Gold試験において、Collectorsクラスは最も複雑で、かつ配点が高い難所です。特に「引数が1つのメソッド」と「引数が2つ以上のメソッド」の違いがよく問われます。
46番から65番までのサンプルコードを、試験頻出順に整理して解説します。
46-53: 基本的な収集・連結¶
Java
List<String> list = List.of("A", "B", "C", "A");
// 46-47. toList, toSet
List<String> listRes = list.stream().collect(Collectors.toList());
Set<String> setRes = list.stream().collect(Collectors.toSet()); // [A, B, C]
// 48. toCollection: 特定の実装クラス(TreeSetなど)を指定
TreeSet<String> treeSet = list.stream().collect(Collectors.toCollection(TreeSet::new));
// 49. toMap (基本): キーと値を指定
// 注意: キーが重複すると IllegalStateException が発生する
Map<String, Integer> map = list.stream().distinct().collect(Collectors.toMap(s -> s, String::length));
// 51-53. joining: 文字列の結合
String s51 = list.stream().collect(Collectors.joining()); // "ABCA"
String s52 = list.stream().collect(Collectors.joining(",")); // "A,B,C,A"
String s53 = list.stream().collect(Collectors.joining("-", "[", "]")); // "[A-B-C-A]"
54-58: 集計・統計¶
Java
List<String> items = List.of("apple", "banana", "cherry");
// 54-55. summingInt / averagingInt
Integer totalLen = items.stream().collect(Collectors.summingInt(String::length));
Double avgLen = items.stream().collect(Collectors.averagingInt(String::length));
// 56. summarizingInt: 合計、平均、最大、最小、個数を一括取得
IntSummaryStatistics stats = items.stream().collect(Collectors.summarizingInt(String::length));
// stats.getAverage(), stats.getMax() などが使える
// 57. counting: 要素数をカウント
long count = items.stream().collect(Collectors.counting());
59-61: グループ化と分割(最重要)¶
Java
List<String> names = List.of("Alice", "Bob", "Charlie", "Amy");
// 59. groupingBy (1引数): 指定したキーでリストを分類
// 戻り値: Map<K, List<T>>
Map<Character, List<String>> group = names.stream()
.collect(Collectors.groupingBy(s -> s.charAt(0)));
// {A=[Alice, Amy], B=[Bob], C=[Charlie]}
// 60. groupingBy (2引数): 下流(downstream)コレクタを指定
// 例:頭文字ごとに「個数」をカウントする
Map<Character, Long> counts = names.stream()
.collect(Collectors.groupingBy(s -> s.charAt(0), Collectors.counting()));
// 61. partitioningBy: Predicateでtrueとfalseの2組に分ける
// 戻り値: Map<Boolean, List<T>>。必ずキーは true と false の2つになる
Map<Boolean, List<String>> partition = names.stream()
.collect(Collectors.partitioningBy(s -> s.length() > 4));
62-65: 特殊・複合操作 (Java 9+)¶
Java
// 62. mapping: 集計の途中で型を変換する
// 例:頭文字でグループ化し、名前の「長さ」のセットを作る
Map<Character, Set<Integer>> lengthsByInitial = names.stream()
.collect(Collectors.groupingBy(s -> s.charAt(0),
Collectors.mapping(String::length, Collectors.toSet())));
// 63. filtering (Java 9): 集計時にさらに条件を適用
Map<Character, List<String>> filteredGroup = names.stream()
.collect(Collectors.groupingBy(s -> s.charAt(0),
Collectors.filtering(s -> s.length() > 3, Collectors.toList())));
// 65. collectingAndThen: 集計完了後に別の処理を適用
// 例:リストに変換した後、変更不能なリストにする
List<String> unmodifiable = names.stream()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
💡 Java Gold 試験対策の急所¶
groupingBy と partitioningBy の違い¶
試験では、戻り値の型を記述させる(または選択する)問題がよく出ます。
groupingBy: キーは任意。該当する要素がないキーは Map に含まれない。partitioningBy: キーは **必ずBoolean**。該当する要素がなくても、trueとfalse両方のキーが必ず Map に存在する(値は空のリスト)。
下流(Downstream)コレクタの連鎖¶
groupingBy(Function, Collector) の第2引数に、さらに groupingBy や mapping を入れる構造は非常に頻出です。
例: 「部署ごとにグループ化し(第1)、その中で役職ごとにグループ化する(第2)」といった多段階集計を読めるようにしておきましょう。
次は、並列Streamや、試験で特に狙われる「ひっかけ問題(66-100)」の解説に進みますか?