completablefuture - java 8 promise
CompletableFuture | thenApply vs thenCompose (4)
No puedo entender la diferencia entre
thenApply(
) y
thenCompose()
.
Entonces, ¿alguien podría proporcionar un caso de uso válido?
De los documentos de Java:
thenApply(Function<? super T,? extends U> fn)
Devuelve un nuevo
CompletionStage
que, cuando esta etapa se completa normalmente, se ejecuta con el resultado de esta etapa como argumento para la función proporcionada.
thenCompose(Function<? super T,? extends CompletionStage<U>> fn)
Devuelve un nuevo
CompletionStage
que, cuando esta etapa se completa normalmente, se ejecuta con esta etapa como argumento de la función proporcionada.
Entiendo que el segundo argumento de
thenCompose
extiende el CompletionStage donde
thenApply
no.
¿Alguien podría proporcionar un ejemplo en cuyo caso tengo que usar
thenApply
y cuando
thenCompose
?
Creo que la respuesta publicada por @Joe C es engañosa.
Permítanme tratar de explicar la diferencia entre
thenApply
y
thenCompose
con un ejemplo.
Supongamos que tenemos 2 métodos:
getUserInfo(int userId)
y
getUserRating(UserInfo userInfo)
:
public CompletableFuture<UserInfo> userInfo = getUserInfo(userId)
public CompletableFuture<UserRating> getUserRating(UserInfo)
Ambos tipos de retorno de método son
CompletableFuture
.
Queremos llamar a
getUserInfo()
primero, y al finalizar, llame a
getUserRating()
con el
UserInfo
resultante.
Al completar el método
getUserInfo()
, intentemos
thenApply
thenCompose
.
La diferencia está en los tipos de devolución:
CompletableFuture<CompletableFuture<UserRating>> f =
userInfo.thenApply(this::getUserRating);
CompletableFuture<UserRating> relevanceFuture =
userInfo.thenCompose(this::getUserRating);
thenCompose()
funciona como
el
flatMap
de Scala
que aplana futuros anidados.
thenApply()
devolvió los futuros anidados como estaban, pero
thenCompose()
aplanó los
CompletableFutures
anidados para que sea más fácil encadenar más llamadas a métodos.
Los Javadocs actualizados en Java 9 probablemente ayudarán a entenderlo mejor:
thenApply
<U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn)
Devuelve un nuevo
CompletionStage
que, cuando esta etapa se completa normalmente, se ejecuta con el resultado de esta etapa como argumento para la función proporcionada.Este método es análogo a
Optional.map
yStream.map
.Consulte la documentación de
CompletionStage
para conocer las reglas que cubren la finalización excepcional.
thenCompose
<U> CompletionStage<U> thenCompose(Function<? super T,? extends CompletionStage<U>> fn)
Devuelve un nuevo
CompletionStage
que se completa con el mismo valor queCompletionStage
devuelto por la función dada.Cuando esta etapa se completa normalmente, la función dada se invoca con el resultado de esta etapa como argumento, devolviendo otro
CompletionStage
. Cuando esa etapa se completa normalmente, elCompletionStage
devuelto por este método se completa con el mismo valor.Para garantizar el progreso, la función proporcionada debe organizar la finalización eventual de su resultado.
Este método es análogo a
Optional.flatMap
yStream.flatMap
.Consulte la documentación de
CompletionStage
para conocer las reglas que cubren la finalización excepcional.
thenApply
se usa si tiene una función de mapeo síncrono.
CompletableFuture<Integer> future =
CompletableFuture.supplyAsync(() -> 1)
.thenApply(x -> x+1);
thenCompose
se usa si tiene una función de mapeo asíncrono (es decir, una que devuelve un
CompletableFuture
).
Luego devolverá un futuro con el resultado directamente, en lugar de un futuro anidado.
CompletableFuture<Integer> future =
CompletableFuture.supplyAsync(() -> 1)
.thenCompose(x -> CompletableFuture.supplyAsync(() -> x+1));
thenApply
y
thenCompose
se
thenCompose
en un
CompletableFuture
y hace algo con su resultado al proporcionar una
Function
.
thenApply
y
thenCompose
ambos devuelven un
CompletableFuture
como su propio resultado, de modo que puede encadenar multiples
thenApply
o
thenCompose
, cada uno tendría una
Function
haciendo algo al resultado de la última
Function
.
Esta
Function
veces necesita hacer algo de forma sincrónica y devolver un resultado, en cuyo caso se debe usar
thenApply
.
CompletableFuture.completedFuture(1)
.thenApply((x)->x+1) // adding one to the result synchronously
.thenApply((x)->System.println(x));
También puede hacer algo asincrónico en esta
Function
, y esta cosa asincrónica que haga debe devolver un
CompletionStage
.
La siguiente
Function
en la cadena no está interesada en obtener un
CompletionStage
como entrada, sino más bien el resultado de ese
CompletionStage
.
Entonces deberías usar
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
puede aceptar una función, que devuelve un valor o una
Promise
de un valor.
En Java debido a las reglas de tipo, las dos funciones tienen que estar claramente tipadas, es decir.
(Function<? super T,? extends U> fn
y la
Function<? super T,? extends CompletionStage<U>> fn
. (O que Java tiene que hacer algún tipo de verificación para hacer algo especial si devuelve un
CompletionStage
, pero eligió el primero) El resultado final es,
Promise.then
se implementa en dos partes, luego
thenApply
y luego
thenCompose
.
También puede leer
mi respuesta
sobre
thenApplyAsync
si eso es confuso para usted.