はじめに:なぜ flatMap を覚えるべきなのか?
Java の Stream API を学ぶと、必ずぶつかるものがあります。それが flatMap です。
「map はなんとなくわかったけど、flatMap は急に難しくなる…」
「なんで List の中の List を扱うときに flatMap を使うの?」
こんな声をよく聞きます。
でも実は、flatMap が苦手なのは 概念を理解できていないだけ です。
仕組みがわかれば、あなたの Java コードは一気にレベルアップします。
この記事では、
map と flatMap の違い → 基本 → 実践例 → ベストプラクティス
の順番で、完全に理解できるように解説していきます。
Java プログラマーを目指す人や、転職を考えている人にとって、flatMap は避けて通れないポイントです。ぜひ最後まで読んでください。
map と flatMap の違いを直感的に理解しよう
まずはこの二つの違いをシンプルに説明します。
● map は「変換」
ひとつの値を、別の値に変換します。
例:
A → a
B → b
C → c
● flatMap は「変換 + 平らに伸ばす」
ひとつの値から、複数の値が出てくるときに使います。
例:
A → a a a
B → b b
C → c
ただし、そのままだと入れ子構造(List の中に List)ができてしまうので、
flat(平ら)に伸ばしてひとつの Stream にする
というのが flatMap の役割です。
とても大事なポイントなので覚えてください:
map は 値 → 値
flatMap は 値 → 複数の値(そして平坦化)
flatMap の基本的な使い方
では、コードを使って理解していきましょう。
◆ 例:List の中に List があるケース
List<List<String>> fruits = List.of(
List.of("Apple", "Apricot"),
List.of("Banana"),
List.of("Cherry", "Cranberry")
);
List<String> result = fruits.stream()
.flatMap(list -> list.stream())
.toList();
System.out.println(result);
// [Apple, Apricot, Banana, Cherry, Cranberry]
もし map を使うと、こうなります。
fruits.stream()
.map(list -> list.stream())
.toList();
// Stream<Stream<String>> になってしまう
map ではネストが残り、扱いにくい構造になります。
そこで flatMap を使うと「平ら」にできます。
実践例1:文章を単語に分解
プログラムで文章を単語に分けたいとします。
List<String> sentences = List.of(
"Java is fun",
"Stream API is powerful"
);
List<String> words = sentences.stream()
.flatMap(sentence -> Arrays.stream(sentence.split(" ")))
.toList();
System.out.println(words);
// [Java, is, fun, Stream, API, is, powerful]
ここでも、
「文章」→「単語の配列」
という変換が起きるため、flatMap が必要になります。
実践例2:社員 → スキルの平坦化
現場の開発では、次のような構造がよくあります。
- 社員
このようなデータを SQL の JOIN なしで処理したい場合、flatMap が役に立ちます。
◆ モデルクラス
class Employee {
String name;
List<String> skills;
Employee(String name, List<String> skills) {
this.name = name;
this.skills = skills;
}
List<String> getSkills() {
return skills;
}
}
◆ flatMap を使って全スキル一覧を取得
List<Employee> employees = List.of(
new Employee("Alice", List.of("Java", "Spring")),
new Employee("Bob", List.of("JavaScript")),
new Employee("Charlie", List.of("Java", "Docker"))
);
List<String> allSkills = employees.stream()
.flatMap(e -> e.getSkills().stream())
.distinct()
.toList();
System.out.println(allSkills);
// [Java, Spring, JavaScript, Docker]
flatMap によって
社員 → 保有スキル
がひとつの Stream になり、扱いやすい形になります。
flatMap の派生メソッド
flatMap には次のような派生があります。
- flatMapToInt
- flatMapToDouble
- flatMapToLong
プリミティブのストリームに変換したいときに使用します。
例:
flatMapToInt(user -> user.getScores().stream().mapToInt(Integer::intValue))
プリミティブ型のストリームは高速なので、処理が多い場合はこちらが有効です。
flatMap を使うときの注意点
flatMap はとても強力なメソッドですが、使い方を間違えるとコードが読みにくくなります。
● 注意1:複雑な処理を flatMap 内で書かない
ラムダ式の中に複雑なコードを書くと、可読性が落ちます。
● 注意2:null に注意
flatMap 内で null を返すのは厳禁です。
必ず emptyStream() を返すようにしましょう。
return Stream.empty();
● 注意3:型が複雑になりすぎるとエラーが増える
flatMap の戻り値は
Stream<何か>
でなければならないため、型が正しいか常に意識してください。
まとめ:flatMap を使いこなせばプログラマーとして一段レベルアップする
flatMap を理解すれば、以下がスムーズに書けるようになります。
- ネストしたリストの処理
- 文章 → 単語の展開
- オブジェクトのネスト構造の展開
- SQL に頼らないデータ変換
Java プログラマーとして大きな武器になるメソッドです。
📚 学習の次のステップ
flatMap や Stream API をさらに深く理解するために、まずは
👉 「絶対にJavaプログラマーになりたい人へ。」
を読んでみてください。
自己学習に最適で、コードの考え方を理解する助けになります。
そして、
- 読んでも理解できない部分がある
- ソースコードレビューをしてほしい
- Java プログラマーとして転職したい
- 転職サポートまで受けたい
という方は、
👉 サイゼントアカデミー
がおすすめです。
現役エンジニアが、学習と転職を徹底サポートします。


コメント