CompletableFuture | thenApply vs thenCompose


119

thenApply()との違いを理解できませんthenCompose()

それで、誰かが有効なユースケースを提供できますか?

Javaドキュメントから:

thenApply(Function<? super T,? extends U> fn)

CompletionStageこのステージが正常に完了すると、指定された関数の引数としてこのステージの結果を使用して実行される新しいを返します。

thenCompose(Function<? super T,? extends CompletionStage<U>> fn)

CompletionStageこのステージが正常に完了すると、指定された関数の引数としてこのステージを使用して実行される新しいを返します。

の2番目の引数がthenComposeCompletionStage を拡張していて、拡張してthenApplyいないことがわかります。

誰かが私が使用thenApplyしなければならない場合の例を提供できthenComposeますか?


39
あなたは違いを理解してくださいmapflatMapではStreamthenApplyであるmapthenComposeあるflatMapCompletableFuturethenComposeを避けるために使用しCompletableFuture<CompletableFuture<..>>ます。
ミーシャ2017年

2
@Mishaコメントありがとうございます。はい、私は違いを知っているmapflatMap、私はあなたのポイントを取得します。ありがとうございました:)
GuyT 2017年

これは、CompletableFuture-baeldung.com/java- completablefuture
錬金術師

回答:


168

thenApply 同期マッピング機能がある場合に使用されます。

CompletableFuture<Integer> future = 
    CompletableFuture.supplyAsync(() -> 1)
                     .thenApply(x -> x+1);

thenCompose 非同期マッピング関数(つまり、 CompletableFuture。次に、ネストされたフューチャーではなく、結果とともにフューチャーを直接返します。

CompletableFuture<Integer> future = 
    CompletableFuture.supplyAsync(() -> 1)
                     .thenCompose(x -> CompletableFuture.supplyAsync(() -> x+1));

14
なぜプログラマは.thenCompose(x -> CompletableFuture.supplyAsync(() -> x+1))代わりに使うべき.thenApplyAsync(x -> x+1)ですか?同期または非同期であること、関連する違いではありません
Holger

17
彼らはそのようにはしません。ただし、使用したサードパーティのライブラリがを返したCompletableFuture場合、これがthenCompose構造をフラット化する方法になります。
ジョーC

1
@ArunavSanyal、投票は別の絵を示しています。この答えは明確で簡潔です。
Alex Shesterov

@Holgerは、thenApplyAsyncあなたが思っているものではないために混乱している場合は、他の回答を読んでください。
1283822

@ 1283822何があなたを私が混乱させたと思わせるのか分かりません、そしてあなたの答えには「あなたがそう思っているものではない」というあなたの主張を裏付けるものは何もありません。
Holger 2018

49

@Joe Cが投稿した回答は誤解を招くと思います。

私は違いを説明してみましょう間thenApplythenComposeの例で。

2つのメソッドがあるとします:getUserInfo(int userId)getUserRating(UserInfo userInfo)

public CompletableFuture<UserInfo> getUserInfo(userId)

public CompletableFuture<UserRating> getUserRating(UserInfo)

どちらのメソッドの戻り型も CompletableFutureです。

getUserInfo()最初に呼び出しを行い、その完了時にgetUserRating()、結果のUserInfo

getUserInfo()メソッドが完成したら、との両方thenApplyを試してみましょうthenCompose。違いは戻り型にあります:

CompletableFuture<CompletableFuture<UserRating>> f =
    userInfo.thenApply(this::getUserRating);

CompletableFuture<UserRating> relevanceFuture =
    userInfo.thenCompose(this::getUserRating);

thenCompose()ネストされたフューチャーをフラット化するScalaのflatMapように機能します。

thenApply()ネストされたフューチャーをそのまま返しましたが、ネストされたフューチャーをthenCompose()フラット化して、CompletableFuturesより多くのメソッド呼び出しをチェーン化しやすくしました。


2
その後、ジョーCの答えは誤解を招くものではありません。それは正しく、より簡潔です。
koleS 2018年

2
これは非常に役に立ちました:-)
dstibbe

1
Imho CompletableFuture <UserInfo> getUserInfoとCompletableFuture <UserRating> getUserRating(UserInfo)\\を書くのはデザインが悪いです代わりに、非同期でチェーンしたい場合はUserInfo getUserInfo()とint getUserRating(UserInfo)でなければなりません。 ompletableFuture.supplyAsync(x => getUserInfo(userId))。thenApply(userInfo => getUserRating(userInfo))またはこのようなものを使用すると、より読みやすくなり、すべての戻り型をCompletableFuture
user1694306

@ user1694306設計が悪いかどうかは、ユーザーの評価がに含まれているUserInfoか(そうである場合)か、個別に取得する必要があるか(場合によってはコストがかかる場合もある)によって異なります。
glglgl

42

Java 9で更新されたJavadocは、おそらくそれをよりよく理解するのに役立ちます。

thenApply

<U> CompletionStage<U> thenApply​(Function<? super T,? extends U> fn)

CompletionStageこのステージが正常に完了すると、指定された関数の引数としてこのステージの結果を使用して実行される新しいを返します。

このメソッドはOptional.mapおよびに類似していStream.mapます。

CompletionStage例外的な完了に関する規則については、ドキュメントを参照してください。

thenCompose

<U> CompletionStage<U> thenCompose​(Function<? super T,? extends CompletionStage<U>> fn)

指定された関数によって返されたものCompletionStageと同じ値で完了した新しいものを返しますCompletionStage

このステージが正常に完了すると、このステージの結果を引数として指定された関数が呼び出され、別のが返され CompletionStageます。そのステージが正常に完了すると、 CompletionStageこのメソッドによって返される値は同じ値で完了します。

確実に進行するために、提供された関数は結果の最終的な完了を調整する必要があります。

このメソッドはOptional.flatMapおよびに類似してい Stream.flatMapます。

CompletionStage例外的な完了に関する規則については、ドキュメントを参照してください。


14
彼らはそれらの機能に名前を付けていなかった私はなぜだろうmapflatMap最初の場所で。
Matthias Braun

1
@MatthiasBraunそれは理由だと思う thenApply()は単にを呼び出すFunction.apply()thenCompose()あり、関数の作成に少し似ているます。
Didier L

14

thenApplyおよびのthenComposeメソッドですCompletableFuture。でCompleteableFuture結果に何かをするつもりの場合に使用しますFunction

thenApplyそして、thenComposeの両方が返されCompletableFuture、自分の結果として。複数thenApplyまたはthenCompose一緒にチェーンできます。Function各呼び出しにa を指定します。その結果は次への入力になりFunctionます。

Functionあなたは時々供給は同期何かをする必要があります。の戻り型はFunctionFuture型でなければなりません。この場合、を使用する必要がありますthenApply

CompletableFuture.completedFuture(1)
    .thenApply((x)->x+1) // adding one to the result synchronously, returns int
    .thenApply((y)->System.println(y)); // value of y is 1 + 1 = 2

場合によっては、これで非同期処理を実行することもできますFunction。その場合はを使用する必要がありますthenCompose。の戻り値の型はであるFunction必要がありCompletionStageます。Functionチェーンの次は、その結果をCompletionStage入力として取得し、をアンラップしCompletionStageます。

// addOneAsync may be implemented by using another thread, or calling a remote method
abstract CompletableFuture<Integer> addOneAsync(int input);

CompletableFuture.completedFuture(1)
    .thenCompose((x)->addOneAsync(x)) // doing something asynchronous, returns CompletableFuture<Integer>
    .thenApply((y)->System.println(y)); // y is an Integer, the result of CompletableFuture<Integer> above

これはJavascriptのアイデアに似ていPromiseます。Promise.thenは、値または値のいずれかを返す関数を受け入れることができPromiseます。Javaでこれら2つのメソッドの名前が異なる理由は、一般的な消去によるものです。です。Function<? super T,? extends U> fnFunction<? super T,? extends CompletionStage<U>> fn同じランタイムタイプと見なされFunctionます- 。したがってthenApplythenCompose明確に名前を付ける必要があります。そうしないと、Javaコンパイラが同一のメソッドシグネチャについて文句を言うでしょう。最終結果ビーイングは、JavascriptののはPromise.then二つの部分に実装されて- thenApplythenCompose- Javaで。

あなたは読むことができます 関連する機能についても混乱している場合は、他の回答thenApplyAsync

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.