Je ne comprends pas très bien la différence entre thenApply(
) et thenCompose()
.
Alors, quelqu'un pourrait-il fournir un cas d'utilisation valide?
À partir de la documentation Java:
thenApply(Function<? super T,? extends U> fn)
Retourne un nouveau
CompletionStage
qui, lorsque cette étape se termine normalement, est exécuté avec le résultat de cette étape en tant qu'argument de la fonction fournie.
thenCompose(Function<? super T,? extends CompletionStage<U>> fn)
Renvoie un nouveau
CompletionStage
qui, lorsque cette étape se termine normalement, est exécuté avec cette étape en tant qu'argument de la fonction fournie.
Je comprends que le deuxième argument de thenCompose
étend le CompletionStage alors que thenApply
ne le fait pas.
Quelqu'un pourrait-il donner un exemple, auquel cas je dois utiliser thenApply
et quand thenCompose
?
thenApply
est utilisé si vous avez une fonction de mappage synchrone.
CompletableFuture<Integer> future =
CompletableFuture.supplyAsync(() -> 1)
.thenApply(x -> x+1);
thenCompose
est utilisé si vous avez une fonction de mappage asynchrone (c'est-à-dire une fonction qui renvoie un CompletableFuture
). Il renverra ensuite un avenir avec le résultat directement, plutôt qu'un avenir imbriqué.
CompletableFuture<Integer> future =
CompletableFuture.supplyAsync(() -> 1)
.thenCompose(x -> CompletableFuture.supplyAsync(() -> x+1));
Les Javadocs mis à jour dans Java 9 aideront probablement à mieux le comprendre:
<U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn)
Renvoie une nouvelle
CompletionStage
qui, lorsque cette étape se termine normalement, est exécutée avec le résultat de cette étape en tant qu'argument de la fonction fournie.Cette méthode est analogue à
Optional.map
et àStream.map
.Consultez la documentation
CompletionStage
pour connaître les règles relatives à l'achèvement exceptionnel.
_<U> CompletionStage<U> thenCompose(Function<? super T,? extends CompletionStage<U>> fn)
_
Retourne un nouveau
CompletionStage
qui est complété avec la même valeur que leCompletionStage
renvoyé par la fonction donnée.Lorsque cette étape se termine normalement, la fonction donnée est invoquée avec le résultat de cette étape comme argument, renvoyant un autre
CompletionStage
. Lorsque cette étape se termine normalement, leCompletionStage
renvoyé par cette méthode est complété avec la même valeur.Pour garantir les progrès, la fonction fournie doit organiser la réalisation éventuelle de son résultat.
Cette méthode est analogue à
Optional.flatMap
et àStream.flatMap
.Consultez la documentation
CompletionStage
pour connaître les règles relatives à l'achèvement exceptionnel.
Je pense que la réponse postée par @Joe C est trompeuse.
Laissez-moi essayer d’expliquer la différence entre thenApply
et thenCompose
avec un exemple.
Supposons que nous ayons 2 méthodes: getUserInfo(int userId)
et getUserRating(UserInfo userInfo)
:
public CompletableFuture<UserInfo> userInfo = getUserInfo(userId)
public CompletableFuture<UserRating> getUserRating(UserInfo)
Les deux types de retour de méthode sont CompletableFuture
.
Nous voulons d'abord appeler getUserInfo()
puis, une fois l'opération terminée, appeler getUserRating()
avec le UserInfo
résultant.
À la fin de la méthode getUserInfo()
, essayons à la fois thenApply
et thenCompose
. La différence est dans les types de retour:
CompletableFuture<CompletableFuture<UserRating>> f =
userInfo.thenApply(this::getUserRating);
CompletableFuture<UserRating> relevanceFuture =
userInfo.thenCompose(this::getUserRating);
thenCompose()
fonctionne comme Scala flatMap
qui aplatit les futurs imbriqués.
thenApply()
a renvoyé les futurs imbriqués tels qu'ils étaient, mais thenCompose()
aplatit le CompletableFutures
imbriqué afin qu'il soit plus facile de chaîner davantage d'appels de méthode.
thenApply
et thenCompose
est appelé sur un CompletableFuture
et fait quelque chose avec son résultat en fournissant un Function
. thenApply
et thenCompose
renvoient chacun un CompletableFuture
comme leur propre résultat, de sorte que vous puissiez chaîner plusieurs thenApply
ou thenCompose
, chacun ayant un Function
faisant quelque chose pour le dernier Function
.
Ce Function
doit parfois faire quelque chose de manière synchrone et renvoyer un résultat, auquel cas thenApply
doit être utilisé.
CompletableFuture.completedFuture(1)
.thenApply((x)->x+1) // adding one to the result synchronously
.thenApply((x)->System.println(x));
Vous pouvez également faire quelque chose d'asynchrone dans cette Function
, et cette chose asynchrone que vous faites devrait retourner un CompletionStage
. Le prochain Function
de la chaîne ne souhaite pas obtenir un CompletionStage
en entrée, mais plutôt le résultat de ce CompletionStage
. Donc, alors vous devriez utiliser 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));
En Javascript, Promise.then
peut accepter une fonction qui renvoie soit une valeur, soit un Promise
d'une valeur. Dans Java à cause des règles de type, les deux fonctions doivent être typées séparément, c'est-à-dire. (Function<? super T,? extends U> fn
et Function<? super T,? extends CompletionStage<U>> fn
. (ou que Java doit faire une vérification de type pour faire quelque chose de spécial si vous retournez un CompletionStage
, mais ils ont choisi l'ancien) Le résultat final étant, Promise.then
est implémenté en deux parties thenApply
et thenCompose
.
Vous pouvez également lire ma réponse à propos de thenApplyAsync
si cela vous confond.