CompletableFuture | thenApply 대 thenCompose


119

thenApply()와 thenCompose(). 의 차이에 대해 머리를 이해할 수 없습니다 .

그렇다면 누군가 유효한 사용 사례를 제공 할 수 있습니까?

Java 문서에서 :

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

CompletionStage이 단계가 정상적으로 완료되면 제공된 함수에 대한 인수로이 단계의 결과를 사용하여 실행 되는 new 를 반환 합니다.

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

CompletionStage이 단계가 정상적으로 완료되면 제공된 함수에 대한 인수로이 단계를 사용하여 실행 되는 new 를 리턴 합니다.

두 번째 인수 thenCompose는 CompletionStage 를 확장 thenApply하지 않는 곳 입니다.

누군가 내가 thenApply언제 사용해야하는 경우에 대한 예를 제공 할 수 thenCompose있습니까?


39
당신은 차이 이해 하는가 mapflatMap의를 Stream? thenApply입니다 mapthenCompose는 IS flatMapCompletableFuture. 당신 thenComposeCompletableFuture<CompletableFuture<..>>.
Misha 2017 년

2
@Misha 귀하의 의견에 감사드립니다. 예, map과 의 차이점을 알고 flatMap있습니다. 다시 한 번 감사드립니다 :)
GuyT

답변:


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구조를 평탄화하는 방법이 될 것입니다.
Joe C

1
@ArunavSanyal, 투표는 다른 그림을 보여줍니다. 이 대답은 명확하고 간결합니다.
Alex Shesterov

@Holger thenApplyAsync는 당신이 생각하는 것이 아니기 때문에 혼란 스러우면 내 다른 대답을 읽으십시오 .
1283822

@ 1283822 나는 당신이 내가 혼란 스러웠다 고 생각하게 만드는 이유를 모르겠고 "당신이 생각하는 것이 아닙니다"라는 당신의 주장을 뒷받침하는 당신의 대답에 아무것도 없습니다.
Holger

49

@Joe C가 올린 답변이 오해의 소지가 있다고 생각합니다.

나 사이의 차이를 설명하려고하자 thenApplythenCompose예와 함께.

두 가지 방법이 있다고 가정 해 봅시다 : getUserInfo(int userId)and getUserRating(UserInfo userInfo):

public CompletableFuture<UserInfo> getUserInfo(userId)

public CompletableFuture<UserRating> getUserRating(UserInfo)

두 메서드 반환 유형은 모두 CompletableFuture.

getUserInfo()먼저 호출 하고 완료되면 getUserRating()결과 UserInfo.

getUserInfo()메서드 가 완료되면 thenApplythenCompose. 차이점은 반환 유형에 있습니다.

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

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

thenCompose()중첩 된 미래를 평평하게 만드는 스칼라flatMap 처럼 작동합니다 .

thenApply()중첩 된 퓨처를 그대로 반환했지만 더 많은 메서드 호출을 더 쉽게 연결할 수 있도록 중첩 된 퓨처를 thenCompose()평면화 CompletableFutures했습니다.


2
그렇다면 Joe C의 대답은 오해의 소지가 없습니다. 정확하고 더 간결합니다.
koleS

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의 업데이트 된 Javadocs는 아마도이를 더 잘 이해하는 데 도움이 될 것입니다.

그때 적용

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

CompletionStage이 단계가 정상적으로 완료되면 제공된 함수에 대한 인수로이 단계의 결과를 사용하여 실행 되는 new 를 반환 합니다.

이 방법은 유사 Optional.map하고 Stream.map.

CompletionStage예외적 인 완성을 다루는 규칙 은 문서를 참조하십시오 .

thenCompose

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

주어진 함수에 의해 반환 된 CompletionStage것과 동일한 값으로 완성 된 new 를 CompletionStage반환합니다.

이 단계가 정상적으로 완료되면 주어진 함수가이 단계의 결과를 인수로 사용하여 호출되어 다른 CompletionStage. 해당 단계가 정상적으로 완료되면 CompletionStage이 메서드 에서 반환 된 값이 동일한 값으로 완료됩니다.

진행을 보장하기 위해 제공된 함수는 결과의 최종 완료를 정렬해야합니다.

이 방법은 유사 Optional.flatMap하고 Stream.flatMap.

CompletionStage예외적 인 완성을 다루는 규칙 은 문서를 참조하십시오 .


14
그들이 이러한 기능의 이름을하지 않은 이유를 궁금해 map하고 flatMap처음부터입니다.
Matthias Braun

1
@MatthiasBraun 나는 때문에 그의 생각 thenApply()단순히 호출 Function.apply()thenCompose()기능을 구성에 약간 비슷합니다.
Didier L

14

thenApplythenCompose의 메서드입니다 CompletableFuture. .NET으로 CompleteableFuture결과 를 얻기 위해 무언가를 할 때 사용하십시오 Function.

thenApply그리고 thenCompose모두가를 돌려 CompletableFuture자신의 결과로. 여러 개 thenApply또는 thenCompose함께 연결할 수 있습니다 . Function각 호출 에 를 제공하십시오. 그 결과는 다음에 대한 입력이됩니다 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반드시 a 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에서 다른 이름을 갖는 이유는 일반 삭제 때문 입니다. Function<? super T,? extends U> fnFunction<? super T,? extends CompletionStage<U>> fn같은 런타임 타입을 고려 - Function. 따라서 thenApply그리고 thenCompose분명히 이름이되어야한다, 또는 자바 컴파일러는 동일한 메소드 서명에 대해 불평한다. 최종 결과의 존재는, 자바 스크립트의이 Promise.then두 부분으로 구현됩니다 - thenApplythenCompose- 자바.

관련 기능에 대해 혼란 스러우면 다른 답변을 읽을 수 있습니다 thenApplyAsync.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.