programing

컴플리트향후 | 적용과 구성

kingscode 2022. 7. 14. 22:26
반응형

컴플리트향후 | 적용과 구성

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제공된 경우 동기화된 작업이 필요할 수 있습니다.의 반환 타입Functionnon-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와 합니다.PromisePromise.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의 목적을 명확히 할 수 있는 비교는 ApplyApply의 비교라고 생각합니다.동기 매핑이 전달될 때와 비동기 매핑이 전달될 때 각각 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

반응형