将可填写的未来中的异常映射到不同的异常类型?

时间:2015-09-11 01:40:55

标签: java exception completable-future

我使用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复合块中模仿它。这可能吗?

2 个答案:

答案 0 :(得分:2)

您可以使用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();
        }
        throw (RuntimeException) e; // this is sketchy, handle it differently, maybe by wrapping it in a RuntimeException
    }
    return r;
});

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

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

答案 1 :(得分:0)

请注意,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;
});