Java Gold SE11対策:flatMapの落とし穴:ネスト解消の正しい知識

アイキャッチ画像

JavaのStream APIには、map とよく似た flatMap というメソッドがありますが、この2つを正しく使い分けるのはJava Gold SE11の試験でも重要なポイントです。
特に Optional や List<List<T>> のように、ネストされた構造を扱う場面で「flatMapを使うべきかどうか」を判断できる力が問われます。

この記事では、flatMapの動作原理・使用目的・典型例・試験での引っかけポイントまで、徹底的に解説していきます。

1. mapとflatMapの違いとは?

まず基本の比較から整理しましょう。

メソッド入力出力用途
mapT → RStream<R>要素の変換
flatMapT → Stream<R>Stream<R>ネストされた構造を平坦化

例を見てみます:

List<String> words = List.of(“Java”, “Gold”);

List<Stream<Character>> mapped = words.stream()

    .map(word -> word.chars().mapToObj(c -> (char) c))

    .collect(Collectors.toList());  // List<Stream<Character>>

このように、map を使うと Stream<Stream<Character>> になります。

一方、flatMap を使うと:

List<Character> flatMapped = words.stream()

    .flatMap(word -> word.chars().mapToObj(c -> (char) c))

    .collect(Collectors.toList());  // List<Character>

👉 flatMap によって、ネストが「1段階だけ」削除されます。

2. ネストとは?なぜflatMapで解消するの?

Javaでは次のようなネスト構造がよく出てきます:

  • List<List<String>>
  • Stream<Stream<T>>
  • Optional<Optional<T>>

このような構造のままだと扱いづらいため、「中身だけを取り出してひとつにまとめる」処理が必要になります。
それをやってくれるのが flatMap です。

3. List<List<String>> を使った典型例

List<List<String>> nested = List.of(

    List.of(“A”, “B”),

    List.of(“C”, “D”)

);

// mapでは List<Stream<String>> になってしまう

List<Stream<String>> mapped = nested.stream()

    .map(list -> list.stream())

    .collect(Collectors.toList());

// flatMapでネストを解消

List<String> flatMapped = nested.stream()

    .flatMap(list -> list.stream())

    .collect(Collectors.toList());

System.out.println(flatMapped); // [A, B, C, D]

4. Optionalとの連携(Java Goldでも頻出!)

Optional<Optional<T>> もよくあるネスト構造です。
たとえば:

Optional<String> name = Optional.of(“Java”);

Optional<Optional<Integer>> mapped = name.map(s -> Optional.of(s.length()));

Optional<Integer> flatMapped = name.flatMap(s -> Optional.of(s.length()));

👉 map を使うと Optional<Optional<Integer>> になるが、
👉 flatMap を使えば Optional<Integer> になる。

5. flatMapのポイントまとめ

flatMapが必要な場面
Stream<Stream<T>> を扱うとき
List<List<T>> を flatten したいとき
Optional<Optional<T>> を解消したいとき

6. 試験で出やすいひっかけパターン

❌ mapで処理 → ネストされた構造が残る

List<Stream<String>> result = names.stream()

    .map(name -> Stream.of(name.split(“”)))

    .collect(Collectors.toList());  // NG: ネストされたまま

✅ flatMapで処理 → 中身を平坦化

List<String> result = names.stream()

    .flatMap(name -> Stream.of(name.split(“”)))

    .collect(Collectors.toList());  // OK: 平坦化される

まとめチェックリスト

  • map は構造を維持、flatMap はネストを解消する
  • Optional<Optional<T>> や Stream<Stream<T>> は flatMap で1段階のネストを削除できる
  • ネストがないのに flatMap を使うと意味が変わってしまう → 要注意
  • 試験では map().map() か flatMap() のどちらが正しいかを選ばせる問題が出る

おわりに

flatMap は一見すると難しく感じるかもしれませんが、「ネストを1段階だけ削除する」というシンプルな役割を正しく理解していれば、迷うことはありません。
Java Gold SE11の試験では、OptionalやListのネストをどう扱うかが問われるため、flatMap の理解は合格に直結します。