java - CompletableFuture withFallback/只处理一些错误

标签 java java-8 completable-future

我正在通过 CompletableFuture 接收来自服务调用的响应。我想处理服务返回的一些已知异常,例如乐观并发控制冲突。

这是我得到的。有没有更好的不包装异常或使用 SneakyThrows 的方法?包装异常意味着其他异常处理程序必须检查因果链,而不是仅仅使用 instanceof

someService.call(request)
    .handle((response, error) -> {
        if (error == null)
            return CompletableFuture.completedFuture(response);
        else if (error instanceof OCCException)
            return CompletableFuture.completedFuture(makeDefaultResponse());

        CompletableFuture<Response> errorFuture = new CompletableFuture<>();
        errorFuture.completeExceptionally(error);
        return errorFuture;
    }).thenCompose(Function.identity());

同样,有没有一种方法可以在不使用 wrap-unwrap 的情况下复制 guava 的 withFallback?

CompletableFuture<T> withFallback(CompletableFuture<T> future,
                                  Function<Throwable, ? extends CompletableFuture<T>> fallback) {
    return future.handle((response, error) -> {
        if (error == null)
            return CompletableFuture.completedFuture(response);
        else
            return fallback.apply(error);
    }).thenCompose(Function.identity());
}


...
// Here's the first part of the question implemented using withFallback.
// It's a little cleaner, but it still requires wrapping as a future.
withFallback(someService.call(request), error -> {
    if (error instanceof OCCException)
        return CompletableFuture.completedFuture(makeDefaultResponse());

    CompletableFuture<Response> errorFuture = new CompletableFuture<>();
    errorFuture.completeExceptionally(error);
    return errorFuture;
});

为了完整起见,如果我允许包装异常,它会是什么样子。 (我有一个单元测试来验证抛出的异常是否沿着链传播):

someService.call(request)
    .exceptionally(error -> {
        if (error instanceof OCCException)
            return makeDefaultResponse();
        else
            // wrap because error is declared as a checked exception
            throw new RuntimeException(error);
    });

最佳答案

你要求的 Guava 风格的功能可以这样实现:

static <T> CompletableFuture<T> withFallback(CompletableFuture<T> future,
                  Function<Throwable, ? extends CompletableFuture<T>> fallback) {
  return future.handle((response, error) -> error)
    .thenCompose(error -> error!=null? fallback.apply(error): future);
}

两者兼而有之,在我们不想做任何转换的情况下,通过重用源 future 来更紧凑和节省资源。但是为了让调用者有机会在不引入另一个辅助方法的情况下执行相同的操作,更改方法并使用 BiFunction 获取源 future 作为附加参数将非常有用:

static <T> CompletableFuture<T> withFallback(CompletableFuture<T> future,
  BiFunction<CompletableFuture<T>, Throwable, ? extends CompletableFuture<T>>
                                                                      fallback) {
    return future.handle((response, error) -> error)
      .thenCompose(error -> error!=null? fallback.apply(future,error): future);
}

然后你可以像这样使用它:

withFallback(someService.call(request), (f,t) -> t instanceof OCCException?
                  CompletableFuture.completedFuture(makeDefaultResponse()): f)

关于java - CompletableFuture withFallback/只处理一些错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25338376/

相关文章:

java - 迭代 R.string.name

java - Java 8重写时该方法不明确

java - 需要解释,带有嵌套 allOf 的 applyAsync 将 CompletionStage 视为已完成

java - 转换 Java Stream 并返回减少的值

java - 如何使用 Collectors.toMap 获取 Map<Integer,Integer>?

java - 使用可完成的 future 对方法运行基准测试

java - 返回 CompletableFuture<Void> 还是 CompletableFuture<?>?

java - 适配器上的 notifydataSetChanged 将更新新项目,但不会更新现有项目

java:使用缓冲阅读器并检查字符串是否为空

java - 如何正确编码和解码Base64字符串?