ネストしたコレクションに対するflatMap
flatMapを使って、ネストしたリスト、Optionalのチェーン、ファイルの行構造を平坦化します。
「ネストしたコレクションに対するflatMap」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
ネストしたコレクションの問題
ストリームの各要素を別のコレクションにマッピングすると、map の結果は Stream<List<T>> になります。flatMap は内部のストリームを1つのフラットな Stream<T> に結合します。
List<List<Integer>> nested = List.of(List.of(1,2), List.of(3,4), List.of(5));
// With map:
Stream<List<Integer>> s = nested.stream().map(l -> l); // Stream<List<Integer>>
// With flatMap:
Stream<Integer> flat = nested.stream().flatMap(List::stream); // Stream<Integer>
flat.forEach(System.out::println); // 1 2 3 4 5flatMapとmapの違い
map(f) は各要素に f を適用し、結果をラップします。flatMap(f) はストリームを返す f を適用し、それらすべてのストリームを1つに連結します。
// map: List<String> -> Stream<Stream<Character>>
Stream<Stream<Character>> nested = List.of("hi","bye").stream()
.map(s -> s.chars().mapToObj(c -> (char)c));
// flatMap: List<String> -> Stream<Character>
Stream<Character> flat = List.of("hi","bye").stream()
.flatMap(s -> s.chars().mapToObj(c -> (char)c));注文と商品をフラット化する
典型的な用途は、各注文が商品のリストを持つ場合です。すべての注文に含まれる商品を、1つのフラットなストリームとして取得できます。
List<String> allItems = orders.stream()
.flatMap(order -> order.getItems().stream())
.collect(Collectors.toList());
System.out.println(allItems);OptionalとflatMap
Optional に対して stream()(Java 9以降)を使用すると、0個または1個の要素を持つストリームに変換できます。その後、flatMap によって Stream<Optional<T>> を Stream<T> に平坦化できます。
List<Optional<String>> maybes = List.of(Optional.of("a"), Optional.empty(), Optional.of("c"));
List<String> values = maybes.stream()
.flatMap(Optional::stream) // Java 9+
.collect(Collectors.toList());
System.out.println(values); // [a, c]複数ファイルから全行を読み取る
flatMap を使うと、入れ子のループを使わずに、ファイルのリストに含まれるすべての行を1つのストリームへ簡単に連結できます。
List<Path> files = List.of(Path.of("a.txt"), Path.of("b.txt"));
List<String> allLines = files.stream()
.flatMap(p -> {
try { return Files.lines(p); }
catch (IOException e) { return Stream.empty(); }
})
.collect(Collectors.toList());文字列を単語に分割する
各文を単語に分割し、すべての単語を1つのストリームに平坦化して、単語の出現頻度を数えます。
List<String> sentences = List.of("hello world", "java streams rock");
Map<String, Long> freq = sentences.stream()
.flatMap(s -> Arrays.stream(s.split("\\s+")))
.collect(Collectors.groupingBy(w -> w, Collectors.counting()));
System.out.println(freq);Map.entrySetでflatMapを使う
カテゴリから商品のリストへのマップを平坦化し、すべての商品のストリームに変換します。
Map<String, List<String>> catalog = Map.of(
"fruit", List.of("apple","banana"),
"veg", List.of("carrot","pea"));
List<String> all = catalog.values().stream()
.flatMap(List::stream)
.sorted()
.collect(Collectors.toList());
System.out.println(all); // [apple, banana, carrot, pea]flatMapでNullPointerExceptionを回避する
関数がストリームの代わりに null を返す可能性がある場合は、null チェックを行うか、Stream.empty() を返して NullPointerException を回避してください。
departments.stream()
.flatMap(dept -> dept.getEmployees() == null
? Stream.empty()
: dept.getEmployees().stream())
.forEach(System.out::println);flatMapで重複しない単語を数える
flatMap、distinct、count を組み合わせると、データ処理を簡潔に記述できます。
long distinctWords = sentences.stream()
.flatMap(s -> Arrays.stream(s.toLowerCase().split("[^a-z]+")))
.filter(w -> !w.isEmpty())
.distinct()
.count();
System.out.println("Distinct: " + distinctWords);プリミティブストリーム用のflatMapToInt
プリミティブストリームに平坦化するときは、flatMapToInt、flatMapToLong、flatMapToDouble を使用してボクシングを回避します。
int totalQuantity = orders.stream()
.flatMapToInt(order -> order.getItems().stream().mapToInt(Item::getQuantity))
.sum();
System.out.println("Total qty: " + totalQuantity);パフォーマンスに関する注意
各 flatMap 呼び出しはストリームの層を1つ追加します。小さな内部コレクションが多数ある非常に大規模なデータセットでは、オブジェクト生成のオーバーヘッドを減らすために、反復的なアプローチや Spliterator の使用を検討してください。
確認問題
flatMap は map と異なり、何を行いますか?
まとめ
flatMap は各要素をストリームに変換し、すべてのストリームを1つに結合します。ネストしたコレクションの平坦化、Optional の連結、文字列の分割、複数ファイルの読み取りに使用します。ボクシングを回避するには flatMapToInt を使用します。
よくある質問
「ネストしたコレクションに対するflatMap」レッスンは無料ですか?
はい。「ネストしたコレクションに対するflatMap」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「ネストしたコレクションに対するflatMap」で何を学びますか?
flatMapを使って、ネストしたリスト、Optionalのチェーン、ファイルの行構造を平坦化します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「ネストしたコレクションに対するflatMap」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- ネストしたコレクションに対するflatMap
- 並列ストリーム:性能と注意点
- Spliterator:並列処理のための分割
- iterateとgenerateによる無限ストリーム