将可完成的未来的异常映射到不同的异常类型?

Map exception in completable future to a different exception type?

我正在使用 java 8 的可完成期货,我希望能够接受未来抛出的异常并将其转换为不同的异常。

我尝试过的所有复合材料似乎一旦发生异常就会短路。

例如,使用 scala future,我可以做这样的事情:

scala.concurrent.Future<Object> translatedException = ask.recover(new Recover<Object>() {
            @Override public Object recover(final Throwable failure) throws Throwable {
                if (failure instanceof AskTimeoutException) {
                    throw new ApiException(failure);
                }

                throw failure;
            }
        }, actorSystem.dispatcher());

我希望能够在 java 的未来复合块中模仿它。这可能吗?

您可以使用 CompletableFuture#handle(BiFunction)。例如

CompletableFuture<String> ask = CompletableFuture.supplyAsync(() -> {
    throw new IndexOutOfBoundsException();
});
CompletableFuture<String> translatedException = ask.handle((r, e) -> {
    if (e != null) {
        if (e instanceof IndexOutOfBoundsException) {
            throw new IllegalArgumentException();
        }
        // fallback
        if (e instanceof RuntimeException) {
            throw (RuntimeException) e;
        }
        throw new RuntimeException(e);
    }
    return r;
});

如果 ask 完成但出现异常,则 translatedException 将完成并出现可能已转换的异常。否则,它将具有相同的成功结果值。

关于我在代码中的评论,handle 方法需要 BiFunction,其 apply 方法未声明为抛出 Throwable。因此,lambda 主体本身不能抛出 Throwable。参数 e 的类型是 Throwable 所以你不能直接 throw 它。如果你知道它是那种类型,你可以将它转换为 RuntimeException,或者你可以将它包装在 RuntimeExceptionthrow 中。

请注意,e 始终是 java.util.concurrent.CompletionException

CompletableFuture<String> ask = CompletableFuture.supplyAsync(() -> {
    throw new IndexOutOfBoundsException();
});
CompletableFuture<String> translatedException = ask.handle((r, e) -> {
    if (e != null) {
        if (e.getCause() instanceof IndexOutOfBoundsException) {
            throw new IllegalArgumentException();
        }
        throw (RuntimeException) e; // this is sketchy, handle it differently, maybe by wrapping it in a RuntimeException
    }
    return r;
});