【Java学習|豆知識】Java Stream APIを使いこなそう!flatMapで「1対多」のデータ構造をスマートに処理する方法

1. 導入:なぜflatMapが重要なのか

Javaの開発現場で、入れ子構造になったデータ(例:リストの中にリストがある状態)を扱う際、ネストしたfor文で苦労した経験はありませんか?例えば、「注文リストから全注文明細を取り出す」といった処理です。flatMapを使うと、このような「1対多」の変換を1行で記述でき、コードの可読性と保守性を飛躍的に向上させることができます。

2. 基礎知識:flatMapとは何か

flatMapは、Streamの各要素を「別のStream」に変換し、最終的にそれらを一つのStreamに「平坦化(flatten)」する中間操作です。
通常のmapは「1対1」の変換ですが、flatMapは「1対多」の変換を行います。変換先のStreamが複数あっても、最終的にはそれらが連結されて一つのStreamとして出力される仕組みです。

3. 実装と解決策

flatMapを使いこなすには、変換関数が「Streamを返す」ように設計するのがポイントです。
流れとしては以下の通りです。
1. 親となるリストをStream化する。
2. flatMapメソッドに、親要素から子要素のStreamを作成する関数を渡す。
3. 最後にcollectなどで結果をまとめる。

4. サンプルプログラム

以下のコードは、複数の部署(Department)に所属する従業員(Employee)のリストから、全従業員の名前を抽出する例です。

import java.util.List;
import java.util.stream.Collectors;
import java.util.Arrays;

public class FlatMapExample {
public static void main(String[] args) {
// 部署クラスの定義(簡易版)
record Department(String name, List employees) {}

List departments = Arrays.asList(
new Department(“開発部”, Arrays.asList(“佐藤”, “鈴木”)),
new Department(“営業部”, Arrays.asList(“田中”, “高橋”))
);

// flatMapを使って、全従業員のリストを生成
List allEmployees = departments.stream()
// 部署ごとの従業員リストをStreamに変換し、それをflatMapで一つに統合
.flatMap(dept -> dept.employees().stream())
.collect(Collectors.toList());

// 結果を出力
System.out.println(“全従業員: ” + allEmployees);
}
}

5. 応用・注意点

注意点1:Nullの取り扱い
flatMapの変換関数内でnullを返すとNullPointerExceptionが発生します。リストが空の場合はnullではなく空のリストを返すように設計するか、Optionalを活用しましょう。

注意点2:パフォーマンス
非常に巨大なリストをflatMapで平坦化する場合、大量のStreamオブジェクトが生成されるため、メモリ消費に注意が必要です。また、Sequenced Collections(Java 21〜)と併用する場合、元のコレクションの順序が維持される点はメリットですが、計算量には常に意識を向けてください。

現場のヒント:
「1対多」の変換は、DBから取得したデータの加工や、JSONレスポンスの組み立てで頻出します。まずは、ネストしたループをflatMapで書き換える練習から始めてみてください。コードが格段にスッキリするはずです。

コメント

タイトルとURLをコピーしました