컴플리트향후 | 적용과 구성
i i i i i i i i i i i i 。thenApply(
및 )의 개요thenCompose()
그렇다면, 누가 유효한 사용 사례를 제공할 수 있을까요?
Java 문서에서:
thenApply(Function<? super T,? extends U> fn)
반환을 .
CompletionStage
이 단계가 정상적으로 완료되면 이 단계의 결과를 제공된 함수에 대한 인수로 실행합니다.
thenCompose(Function<? super T,? extends CompletionStage<U>> fn)
반환을 .
CompletionStage
이 단계가 정상적으로 완료되면 이 단계를 제공된 함수에 대한 인수로 실행합니다.
했습니다.thenCompose
하여 Completion Stage를 완성합니다.thenApply
지지않않않않
누가 예를 들어줄 수 있나요?thenApply
리리 and and and and and andthenCompose
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));
@Joe C가 올린 답변은 오해의 소지가 있다고 생각합니다.
에는 어떤 가 있는지 .thenApply
★★★★★★★★★★★★★★★★★」thenCompose
예를 들어서.
두 방법이 해 보겠습니다.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()
네스트된 미래를 평평하게 만드는 스칼라처럼요
thenApply()
했지만, '네스트된 선물'은 반환되지 .thenCompose()
를 CompletableFutures
이것에 의해, 보다 많은 메서드 콜을 체인으로 하는 것이 용이하게 됩니다.
Java 9에서 업데이트된 Javadocs를 통해 더 잘 이해할 수 있습니다.
그 후
<U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn)
이 단계가 정상적으로 완료되면 이 단계의 결과를 인수로 사용하여 실행되는 새 스테이지를 지정된 함수에 반환합니다.
이 방법은 및 와 유사합니다.
예외적인 완료에 관한 규칙에 대해서는, 메뉴얼마찬가지입니다.
그 후 컴포지션
<U> CompletionStage<U> thenCompose(Function<? super T,? extends CompletionStage<U>> fn)
다음 값과 동일한 값으로 완료된 새 값을 반환합니다.
CompletionStage
지정된 함수에 의해 반환됩니다.정상적으로 로 하여 되고 다른 됩니다.
CompletionStage
스테이지가 정상적으로되면, 그 스테이지가 으로 종료됩니다CompletionStage
이 메서드에 의해 반환된 값은 동일한 값으로 완료됩니다.진행을 보장하기 위해 제공된 기능은 결과의 최종적인 완료를 준비해야 합니다.
이 방법은 및 와 유사합니다.
예외적인 완료에 관한 규칙에 대해서는, 메뉴얼마찬가지입니다.
thenApply
그리고.thenCompose
의 방식입니다.CompletableFuture
어떤 일을 하려고 할 때 사용하세요.CompletableFuture
의 결과Function
.
thenApply
그리고.thenCompose
둘 다 a를 반환하다CompletableFuture
그들 자신의 결과로서.여러 개를 연결할 수 있습니다.thenApply
또는thenCompose
함께.a를 제공하다Function
그 결과가 다음 콜에 대한 입력이 됩니다.Function
.
그Function
제공된 경우 동기화된 작업이 필요할 수 있습니다.의 반환 타입Function
non-to-no-no-no-no-noFuture
를 입력합니다.이 경우,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의 Javascript와 합니다.Promise
Promise.then
는 값 수 .Promise
가치가 있다.Java에서 이 두 가지 메서드의 이름이 다른 이유는 일반 삭제 때문입니다. Function<? super T,? extends U> fn
★★★★★★★★★★★★★★★★★」Function<? super T,? extends CompletionStage<U>> fn
는 동일한 유형으로됩니다.Function
.따라서thenApply
★★★★★★★★★★★★★★★★★」thenCompose
이름을 명확하게 지정해야 합니다.그렇지 않으면 Java 컴파일러는 동일한 메서드 시그니처에 대해 불만을 제기합니다.★★★★ Javascript입니다Promise.then
하다, 하다, 하다, 하다, 하다, 이렇게 두 합니다.thenApply
★★★★★★★★★★★★★★★★★」thenCompose
(자바).
관련 기능에 대해서도 혼란스러우시다면 다른 답변을 읽어보실 수 있습니다.thenApplyAsync
.
Compose()는 Complete 테이블을 연결하는 데 적합합니다.미래.
그러면 Apply()는 Completable future의 변환 결과에 적합합니다.
두 가지 방법을 모두 사용하여 목표를 달성할 수 있지만, 한 가지 방법이 다른 사용 사례보다 더 적합합니다.
public CompletableFuture<Integer> process(Integer i) {
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(
() -> new HeavyTask(i).execute());
return completableFuture;
}
@SneakyThrows
public CompletableFuture<Integer> thenApplyVsThenCompose() {
// each time calling thenApply() function returns CompletionState
// so you will get nested Futures
// you can think about it like map() java optional
CompletableFuture<Future<Integer>> cf1 = CompletableFuture.supplyAsync(
() -> new HeavyTask().execute())
.thenApply(i -> process(i));
// to get result you will have to get nested get() calls
Integer resultFromThenApply = cf1.get().get();
// when calling thenCompose() nested Futures are flatten
// you can think about it like flatMap() java optional
CompletableFuture<Integer> cf2;
cf2 = CompletableFuture.supplyAsync(
() -> new HeavyTask().execute())
.thenCompose(this::process);
// you have to just call one get() since thenCompose was flatten
Integer resultFromThenCompose = cf2.get();
return null;
}
그 둘 사이의 차이를 시각화할 수 있는 다른 문제
thenApply()/thenCompose()를 적용해야 하는 시간을 모를 경우(재귀 메서드 등) 솔루션을 어떻게 구현하시겠습니까?
public void nested() throws ExecutionException, InterruptedException {
CompletableFuture<Integer> completableFutureToCompose = CompletableFuture.completedFuture(1);
for (int i = 0; i < 10; i++) {
log.info("Composing");
completableFutureToCompose = completableFutureToCompose.thenCompose(this::process);
}
completableFutureToCompose.get();
// not achievable using then apply
CompletableFuture<Integer> completableFutureToApply = CompletableFuture.completedFuture(1);
for (int i = 0; i < 10; i++) {
log.info("Applying");
completableFutureToApply = completableFutureToApply.thenApply(this::process).get();
}
completableFutureToCompose.get();
}
public CompletableFuture<Integer> process(Integer i) {
log.info("PROCESSING");
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(
() -> new HeavyTask(i).execute());
return completableFuture;
}
- 먼저 컴포넌트를 사용하여 미래가 어떻게 다른 것으로 전달되는지를 작성한 후 실행한다.
- 호출을 적용할 때마다 apply를 사용하여 로직을 실행합니다.
JoeC의 답변은 맞지만 Compose의 목적을 명확히 할 수 있는 비교는 Apply와 Apply의 비교라고 생각합니다.동기 매핑이 전달될 때와 비동기 매핑이 전달될 때 각각 1회.
그때 Apply에 전달된 매핑이 문자열(미래가 아니므로 매핑이 동기화됨)을 반환하면 결과는 다음과 같습니다.CompletableFuture<String>
마찬가지로 매핑이 에 전달되면 Complete 테이블이 반환됩니다.Future < String > (미래, 그래서 매핑은 비동기)최종 결과는 다음과 같습니다.CompletableFuture<CompletableFuture<String>>
그것은 불필요한 보금자리이다(미래의 미래는 여전히 미래다!).여기서 Compose를 사용하면 결과에 미래를 중첩하지 않고 여러 비동기 작업을 서로 "합성"(내스트)할 수 있습니다.
private void test1()이 실행을 슬로우합니다.예외, 중단됨예외 {
//thenApply返回的是之前的CompletableFuture
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 1)
.thenApply((x) -> {
x = x + 1;
log.info("thenApply, 1, x:{}", x);
return x;
});
System.out.println(future.get());
}
//thenCompose返回的是新的CompletableFuture
private void test2() throws ExecutionException, InterruptedException {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 1)
.thenCompose((x) -> {
return CompletableFuture.supplyAsync(() -> {
Integer y = x + 1;
log.info("thenCompose, 1, x:{}", y);
return y;
});
});
System.out.println(future.get());
}
그리고 Apply와 Compose를 사용할 때 코드의 실제 차이점과 중첩된 미래 모습이 무엇인지 여전히 혼란스러운 경우 전체 작업 예를 참조하십시오.
package com.graphql.demo.garphqlapi;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
public class ComposeVsThenApply {
public static void main(String[] args) {
ComposeVsThenApply cva = new ComposeVsThenApply();
//thenCompose usage : Using the thenCompose for simplifying the return type of dependent processing.
System.out.println("Starting thenCompose demo");
CompletableFuture<StockRating> flattenedFuture = cva.getStockDetails("Apple").thenCompose((stock) -> {
return cva.getRating(stock);
});
//Retrive results
try {
StockRating stockViaThenCompose = flattenedFuture.get();
System.out.println("\n\t\tStock summery :" + stockViaThenCompose.getStockName() + ", Rating :" + stockViaThenCompose.getRating());
System.out.println("--- thenCompose demo ended ---");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//ThenAply: thenApply is good for result transformation but sucks when we have two asynchronous dependent processing. Now you get nested future.
System.out.println("\n\n\nStarting thenApply demo");
CompletableFuture<CompletableFuture<StockRating>> nestedFuture = cva.getStockDetails("Apple").thenApply((stock) -> {
return cva.getRating(stock);
});
//Retrive results
try {
StockRating stockrViaThenApply = nestedFuture.get().get();
System.out.println("\n\t\tStock summery :" + stockrViaThenApply.getStockName() + ", Rating :" + stockrViaThenApply.getRating());
System.out.println("--- thenApply demo ended---");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
class Stock {
private String name;
public Stock(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class StockRating {
private Double rating;
public boolean isBuyCall() {
return buyCall;
}
public void setBuyCall(boolean buyCall) {
this.buyCall = buyCall;
}
public String getStockName() {
return stockName;
}
public void setStockName(String stockName) {
this.stockName = stockName;
}
private boolean buyCall;
public StockRating(Double rating, boolean buyCall, String stockName) {
this.rating = rating;
this.buyCall = buyCall;
this.stockName = stockName;
}
private String stockName;
public StockRating(Double rating) {
this.rating = rating;
}
public Double getRating() {
return rating;
}
public void setRating(Double rating) {
this.rating = rating;
}
}
class StockSupplier implements Supplier<Stock> {
private String name;
public StockSupplier(String name) {
this.name = name;
}
@Override
public Stock get() {
try {
System.out.println("\n\t\tRetriving details for " + this.name);
TimeUnit.SECONDS.sleep(4);
System.out.println("\n\t\tDone with details retrival for " + this.name);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new Stock(name);
}
}
class RatingSupplier implements Supplier<StockRating> {
private Stock stock;
public RatingSupplier(Stock stock) {
this.stock = stock;
}
@Override
public StockRating get() {
try {
System.out.println("\n\t\tRetriving stock rating for " + this.stock.getName());
TimeUnit.SECONDS.sleep(4);
System.out.println("\n\t\tDone with rating retrival for " + this.stock.getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
return new StockRating(10d, true, this.stock.getName());
}
}
public CompletableFuture<Stock> getStockDetails(String name) {
return CompletableFuture.supplyAsync(new StockSupplier(name));
}
public CompletableFuture<StockRating> getRating(Stock stock) {
return CompletableFuture.supplyAsync(new RatingSupplier(stock));
}
public String getSummeryReport(Stock stock, StockRating sr) {
return stock.getName() + "/n " + sr.getRating();
}
}
이전 단계의 결과를 통해 복잡한 조정을 수행하려는 경우 Compose가 당시 Apply보다 유리할 것으로 알고 있습니다.
다음 예시는 첫 번째 단계의 결과를 통해 계산하기 위해 두 개의 다른 위치로 이동한 것입니다. 누가 더 빨리 돌아오면 두 곳의 차이를 볼 수 있습니다.
CompletableFuture<Integer> result = CompletableFuture.supplyAsync(() -> 1);
// thenCompose
System.out.println(result.thenCompose(i -> CompletableFuture.anyOf(CompletableFuture.supplyAsync(() -> i + 1), CompletableFuture.supplyAsync(() -> i + 2))).join());
System.out.println(result.thenCompose(i -> CompletableFuture.supplyAsync(() -> i + 1).applyToEither(CompletableFuture.supplyAsync(() -> i + 2), j -> j)).join());
// ----- thenApply
System.out.println(result.thenApply(i -> CompletableFuture.anyOf(CompletableFuture.supplyAsync(() -> i + 1), CompletableFuture.supplyAsync(() -> i + 2)).join()).join());
System.out.println(result.thenApply(i -> CompletableFuture.supplyAsync(() -> i + 1).applyToEither(CompletableFuture.supplyAsync(() -> i + 2), j -> j).join()).join());
언급URL : https://stackoverflow.com/questions/43019126/completablefuture-thenapply-vs-thencompose
'programing' 카테고리의 다른 글
이 Vue 계산 속성이 반응하지 않는 이유는 무엇입니까? (0) | 2022.07.14 |
---|---|
한 페이지 어플리케이션 URL 및 django URL 처리 (0) | 2022.07.14 |
업계 표준에서는 #define이 금지되어 있습니까? (0) | 2022.07.14 |
인증되지 않은 vuex 작업에 대한 리디렉션 패턴 (0) | 2022.07.14 |
어떻게 동시에 두 개의 클래스를 묶을 수 있을까요? (0) | 2022.07.14 |