1. 導入
Java 8で導入されたStream APIは、現代のJava開発におけるデータ操作の標準です。しかし、ストリームで加工したデータを「最終的にどのような形式で受け取るか」を決めるのがCollectorsです。多くのエンジニアがtoList()を使うだけで止まっていますが、Collectorsを正しく理解することで、グルーピングや集計処理を驚くほど簡潔に記述でき、可読性と保守性を劇的に向上させることが可能です。
2. 基礎知識
java.util.stream.Collectorsは、Streamの要素を収集(collect)するための便利なメソッド群を提供するクラスです。ストリームは「処理のパイプライン」であり、Collectorsはその終端処理として、ストリーム上のデータをListやSet、Map、あるいは特定の数値(合計や平均)へと変換する役割を担います。Java 21から導入されたSequenced Collectionsも意識することで、順序を維持した効率的なデータ収集が可能になります。
3. 実装/解決策
現場で最も頻出するパターンは、条件に基づいた「Mapへの変換」と「グルーピング」です。例えば、ユーザーリストからIDをキーにしたMapを作成したり、部署ごとにユーザーをまとめたりする処理は、Collectorsを使うことでループ文を一切書かずに実現できます。
4. サンプルプログラム
以下は、ユーザーオブジェクトのリストを「部署ごとのグループ」にまとめ、さらに「名前のリスト」に変換する実用的なコードです。
import java.util.;
import java.util.stream.Collectors;
public class CollectorExample {
record User(String name, String department) {}
public static void main(String[] args) {
List
new User(“Alice”, “Engineering”),
new User(“Bob”, “Sales”),
new User(“Charlie”, “Engineering”)
);
// 部署(Department)ごとにユーザー名をグループ化する
// groupingByでグルーピングし、mappingで名前のみを抽出してListに変換
Map
.collect(Collectors.groupingBy(
User::department,
Collectors.mapping(User::name, Collectors.toList())
));
// 結果の出力
groupedUsers.forEach((dept, names) ->
System.out.println(dept + “: ” + names));
}
}
5. 応用・注意点
実務でCollectorsを利用する際の注意点は、「パフォーマンス」と「並列処理」です。
・Collectors.toUnmodifiableList()の活用: Java 10以降、不変リストを返却するメソッドが追加されました。副作用を防ぐために、可能な限り不変(Immutable)なコレクションを返すことを推奨します。
・並列ストリーム(parallelStream)との併用: 大規模なデータセットに対してgroupingByなどを行う場合、並列処理は強力ですが、スレッドセーフではない操作をCollectors内で行うとバグの温床になります。
・nullの取り扱い: ストリーム内にnullが含まれる場合、toMapなどで例外(NullPointerException)が発生することがあります。事前にfilter(Objects::nonNull)を挟むなど、堅牢なパイプライン構築を心がけてください。
これらを意識するだけで、あなたのJavaコードはより洗練されたものになるはずです。ぜひ今日から積極的に活用してみてください。

コメント