thenApply(
)とthenCompose()
の違いを理解できません。
だから、誰かが有効なユースケースを提供できますか?
Javaドキュメントから:
thenApply(Function<? super T,? extends U> fn)
このステージが正常に完了すると、指定された関数への引数としてこのステージの結果で実行される新しい
CompletionStage
を返します。
thenCompose(Function<? super T,? extends CompletionStage<U>> fn)
このステージが正常に完了すると、指定された関数への引数としてこのステージで実行される新しい
CompletionStage
を返します。
thenCompose
の2番目の引数は、thenApply
が拡張しないCompletionStageを拡張することがわかります。
誰かが例を提供できますか?その場合、thenApply
を使用する必要があり、thenCompose
を使用する必要がありますか?
thenApply
は、同期マッピング関数がある場合に使用されます。
CompletableFuture<Integer> future =
CompletableFuture.supplyAsync(() -> 1)
.thenApply(x -> x+1);
thenCompose
は、非同期マッピング関数(つまり、CompletableFuture
を返す関数)がある場合に使用されます。その後、ネストされたFutureではなく、結果を含むFutureを直接返します。
CompletableFuture<Integer> future =
CompletableFuture.supplyAsync(() -> 1)
.thenCompose(x -> CompletableFuture.supplyAsync(() -> x+1));
Java 9の更新されたJavadocは、おそらくそれをよりよく理解するのに役立つでしょう:
<U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn)
新しい
CompletionStage
を返します。このステージが正常に完了すると、このステージの結果が提供された関数の引数として実行されます。このメソッドは
Optional.map
およびStream.map
に類似しています。例外的な補完に関するルールについては、
CompletionStage
のドキュメントをご覧ください。
<U> CompletionStage<U> thenCompose(Function<? super T,? extends CompletionStage<U>> fn)
新しい
CompletionStage
を返します。これは、指定された関数によって返されたCompletionStage
と同じ値で完了します。このステージが正常に完了すると、このステージの結果を引数として指定された関数が呼び出され、別の
CompletionStage
が返されます。そのステージが正常に完了すると、このメソッドによって返されるCompletionStage
は同じ値で完了します。進行を保証するために、提供された関数は結果の最終的な完了を手配する必要があります。
このメソッドは
Optional.flatMap
およびStream.flatMap
に類似しています。例外的な補完に関するルールについては、
CompletionStage
のドキュメントをご覧ください。
@Joe Cが投稿した回答は誤解を招くと思います。
thenApply
とthenCompose
の違いを例で説明してみましょう。
getUserInfo(int userId)
とgetUserRating(UserInfo userInfo)
の2つのメソッドがあるとします:
public CompletableFuture<UserInfo> userInfo = getUserInfo(userId)
public CompletableFuture<UserRating> getUserRating(UserInfo)
メソッドの戻り値の型は両方ともCompletableFuture
です。
最初にgetUserInfo()
を呼び出し、その完了時に、結果のUserInfo
でgetUserRating()
を呼び出します。
getUserInfo()
メソッドが完了したら、thenApply
とthenCompose
の両方を試してみましょう。違いは戻り型にあります。
CompletableFuture<CompletableFuture<UserRating>> f =
userInfo.thenApply(this::getUserRating);
CompletableFuture<UserRating> relevanceFuture =
userInfo.thenCompose(this::getUserRating);
thenCompose()
は ScalaのflatMap
のように機能し、ネストされた先物をフラット化します。
thenApply()
はネストされたfutureをそのまま返しましたが、thenCompose()
はネストされたCompletableFutures
をフラット化したため、より多くのメソッド呼び出しをチェーン化することが容易になりました。
thenApply
およびthenCompose
は、CompletableFuture
で呼び出され、Function
を指定することで、その結果を処理します。 thenApply
とthenCompose
は、両方とも自分自身の結果としてCompletableFuture
を返します。そのため、複数のthenApply
またはthenCompose
をチェーンでき、それぞれが最後のFunction
の結果に対して何かを行うFunction
を持ちます。
このFunction
は、同期的に何かを行う必要があり、結果を返すことがあります。その場合はthenApply
を使用する必要があります。
CompletableFuture.completedFuture(1)
.thenApply((x)->x+1) // adding one to the result synchronously
.thenApply((x)->System.println(x));
また、このFunction
で何か非同期を行うこともできます。この非同期のことはCompletionStage
を返す必要があります。チェーン内の次のFunction
は、入力としてCompletionStage
を取得するのではなく、そのCompletionStage
の結果に関心があります。したがって、thenCompose
を使用する必要があります。
// addOneAsync may be implemented by using another thread, or calling a remote method
// CompletableFuture<Integer> addOneAsync(int input);
CompletableFuture.completedFuture(1)
.thenCompose((x)->addOneAsync(x)) // doing something asynchronous
.thenApply((x)->System.println(x));
JavaScriptでは、Promise.then
は、値または値のPromise
を返す関数を受け入れることができます。 Javaでは、型の規則により、2つの関数を明確に型付けする必要があります。 (Function<? super T,? extends U> fn
およびFunction<? super T,? extends CompletionStage<U>> fn
。 (または、JavaはCompletionStage
を返す場合、特別なタイプのチェックを行う必要がありますが、前者を選択します)最終結果であるPromise.then
は、2つの部分thenApply
とthenCompose
で実装されます。
my answer about thenApplyAsync
が読みにくい場合は、これも読むことができます。