如何获得whenComplete和thenCompose的组合效果?

Zig*_*oon 5 java java-8

我想拿出来与的综合影响CompletableFuturewhenCompletethenCompose,具体如下:

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

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

Sla*_*law 5

我不相信CompletionStageCompletableFuture为此提供任何单一的方法。但是,如果我正确理解您的要求,结合handlewiththenCompose应该可以满足您的需求。

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

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

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

thenCompose(Function.identity());
Run Code Online (Sandbox Code Playgroud)

这给了我们一个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!");
    }

}
Run Code Online (Sandbox Code Playgroud)

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

注意:上面的所有内容都CompletionStage直接使用界面,但使用CompletableFuture也同样有效(并且可能更可取)。