首页 > 解决方案 > 如何获得whenComplete和thenCompose的组合效果?

问题描述

我正在尝试提出具有 and 组合效果的 CompletableFuture whenCompletethenCompose特别是:

  1. 返回 aCompletionStage而不仅仅是结果,类似于thenCompose.
  2. 即使在前一阶段异常完成时也会执行,类似于whenComplete,并且不会阻止异常传播。

这篇文章接近我想要实现的目标,但我不想使用handle隐藏异常的方法。感谢您的任何想法。

标签: javajava-8

解决方案


我不相信CompletionStageCompletableFuture为此提供任何单一方法。但是,如果我正确理解您的要求,结合handle应该thenCompose做您想做的事。

handle无论父阶段是正常完成还是异常完成,都会执行一个阶段,并分别让您访问结果或错误。从这个阶段开始,您可以返回另一个CompletionStage,它可以正常完成,也可以异常完成,具体取决于handle阶段接收到的参数。

handle((T result, Throwable error) -> {
    if (error != null) {
        return CompletableFuture.<T>failedStage(error);
    } else {
        return processResult(result); // returns CompletionStage<T>
    }
});

现在你有一个CompletionStage<CompletionStage<T>>. 现在我们通过调用执行平面地图操作thenCompose

thenCompose(Function.identity());

这给了我们一个CompletionStage<T>. 这CompletionStage<T>将是 . 返回的任何实例handle。如果该实例是一个失败的阶段,那么异常仍然会传播;否则,结果将传递到依赖于该thenCompose阶段的任何阶段,并且处理正常继续。

您可以通过以下示例看到这一点:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

public class Main {

    public static void main(String[] args) {
        methodThatReturnsCompletionStage()
                .handle((result, error) -> {
                    if (error != null) {
                        return CompletableFuture.<String>failedStage(error);
                    } else {
                        return processResult(result);
                    }
                })
                .thenCompose(future -> {
                    System.out.println("#thenCompose invoked");
                    return future; // Identity function
                })
                .thenApply(result -> {
                    System.out.println("#thenApply invoked");
                    return result; // Identity function (exists to show intermediary stage)
                })
                .whenComplete((result, error) -> {
                    System.out.println("#whenComplete invoked");
                    if (error != null) {
                        error.printStackTrace(System.out);
                    } else {
                        System.out.println(result);
                    };
                });
    }

    private static CompletionStage<String> methodThatReturnsCompletionStage() {
        return CompletableFuture.completedStage("Hello");
        // return CompletableFuture.failedStage(new RuntimeException("OOPS"));
    }

    private static CompletionStage<String> processResult(String result) {
        return CompletableFuture.completedFuture(result + ", World!");
    }

}

这将导致每个阶段都被调用并输出Hello, World!. 但是,如果您切换methodThatReturnsCompletionStage()到返回失败的阶段,thenApply则会跳过(因为未来已失败)并给出异常whenComplete(如handle,为正常或异常完成调用)。

注意:以上所有内容都CompletionStage直接使用接口,但使用CompletableFuture效果也一样好(并且可能更可取)。


推荐阅读