0Pricing
Java Academy · レッスン

thenApply と thenCompose による連鎖

thenApply で結果を変換し、thenCompose で非同期処理を flatMap のように連結して、入れ子の Future を避けます。

「thenApply と thenCompose による連鎖」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

thenApply: 結果を変換する

thenApply(Function) は、完了した future の結果に同期的な関数を適用し、変換後の型を持つ新しい future を返します。新しい非同期タスクは開始しません。

CompletableFuture<String> nameFuture = CompletableFuture
    .supplyAsync(() -> 42L)            // CF<Long>
    .thenApply(id -> "User#" + id);    // CF<String>
System.out.println(nameFuture.join()); // "User#42"

thenApplyAsync: スレッド上で変換する

thenApplyAsync は変換関数を ForkJoinPool(または指定した executor)で実行し、完了処理を行ったスレッドをすぐに解放します。

CompletableFuture<String> result = fetchUserAsync()
    .thenApplyAsync(user -> serialize(user)); // runs on pool thread

thenAccept: 戻り値なしで消費する

thenAccept(Consumer) は結果を処理しますが、CompletableFuture<Void> を返します。値を次の処理に渡す必要がないパイプラインの最後のステップとして使用します。

fetchUserAsync()
    .thenApply(User::getName)
    .thenAccept(name -> System.out.println("Hello, " + name));

thenRun: 完了後に実行する

thenRun(Runnable) は future の完了後にタスクを実行し、結果は無視します。リソースを閉じたり、副作用を発生させたりする場合に適しています。

downloadFileAsync(url)
    .thenRun(() -> System.out.println("Download complete"));

複数の thenApply 呼び出しを連結する

複数の thenApply 呼び出しでパイプラインを形成できます。各ステップは、前のステップの出力を受け取ります。

CompletableFuture<Double> result = CompletableFuture
    .supplyAsync(() -> "  42.5  ")
    .thenApply(String::trim)
    .thenApply(Double::parseDouble)
    .thenApply(d -> d * 1.21); // apply 21% VAT
System.out.println(result.join()); // 51.425

thenCompose: ネストした Future を平坦化する

thenCompose(Function<T, CompletionStage<U>>) は future に対する flatMap のようなものです。ネストした future を平坦化することで、CompletableFuture<CompletableFuture<T>> を回避します。

// Wrong with thenApply — returns CF<CF<Order>>:
CompletableFuture<CompletableFuture<Order>> nested =
    fetchUser(id).thenApply(u -> fetchLatestOrder(u.getId()));
// Correct with thenCompose — returns CF<Order>:
CompletableFuture<Order> flat =
    fetchUser(id).thenCompose(u -> fetchLatestOrder(u.getId()));

逐次的な非同期呼び出しに thenCompose を使う

各非同期ステップが前のステップの結果に依存する場合は thenCompose を使用します。これにより、ステップを結果に依存した逐次処理にできます。

fetchUser(userId)
    .thenCompose(user -> fetchOrders(user.getId()))
    .thenCompose(orders -> computeTotal(orders))
    .thenAccept(total -> System.out.println("Total: " + total));

thenApply と thenCompose の比較

thenApply: T -> U をマッピングします(同期的な変換)。thenCompose: T -> CompletableFuture<U> をマッピングして平坦化します。次のステップも非同期の場合は compose を使用します。

handle で中間エラーを処理する

handle(BiFunction<T, Throwable, U>) は、future が正常に完了した場合も例外で完了した場合も呼び出されるため、パイプラインの途中でエラーからの回復や変換を行えます。

fetchUser(id)
    .thenApply(User::getProfile)
    .handle((profile, ex) -> {
        if (ex != null) return Profile.empty(); // recover
        return profile;
    })
    .thenAccept(System.out::println);

whenComplete: どの結果の後にも副作用を実行する

whenComplete(BiConsumer) は、正常完了または例外完了の後に、ロギングやクリーンアップのために呼び出されます。handle とは異なり、結果を変更しません。

fetchAsync()
    .whenComplete((result, ex) -> {
        if (ex != null) log.error("Failed", ex);
        else            log.info("Result: " + result);
    });

非ブロッキングパイプラインの例

ユーザーを取得し、そのユーザーの注文を取得し、概要を計算するという、完全に非ブロッキングなパイプラインを組み立てます。すべてのステップが非同期で実行され、各ステップは前のステップに依存します。

CompletableFuture<String> summary =
    fetchUser(userId)
        .thenCompose(u -> fetchOrders(u.getId()))
        .thenApply(orders -> orders.size() + " orders")
        .exceptionally(ex -> "Error: " + ex.getMessage());
System.out.println(summary.join());

確認問題

thenApply ではなく thenCompose を使うのはどのような場合ですか。

まとめ

thenApply はパイプライン内の同期的な値を変換します。thenCompose は非同期ステップを連結します(future に対する flatMap です)。handle / whenComplete でエラー処理と副作用を追加します。読みやすさのため、パイプラインは左から右に組み立てます。

よくある質問

「thenApply と thenCompose による連鎖」レッスンは無料ですか?

はい。「thenApply と thenCompose による連鎖」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「thenApply と thenCompose による連鎖」で何を学びますか?

thenApply で結果を変換し、thenCompose で非同期処理を flatMap のように連結して、入れ子の Future を避けます。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「thenApply と thenCompose による連鎖」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. CompletableFuture の作成と完了
  2. thenApply と thenCompose による連鎖
  3. Future の結合:allOf と anyOf
  4. エラー処理と非同期 HTTP パイプライン
← Java Academyに戻る