completionstage completablefuture await async java java-8 completable-future

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 y Stream.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 que CompletionStage 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, el CompletionStage 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 y Stream.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.