java 传递给 CompletableFuture.exceptionally() 的异常处理程序是否必须返回一个有意义的值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37770539/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Does an exception handler passed to CompletableFuture.exceptionally() have to return a meaningful value?
提问by David Moles
I'm used to the ListenableFuture
pattern, with onSuccess()
and onFailure()
callbacks, e.g.
我习惯了ListenableFuture
模式,有onSuccess()
和onFailure()
回调,例如
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
ListenableFuture<String> future = service.submit(...)
Futures.addCallback(future, new FutureCallback<String>() {
public void onSuccess(String result) {
handleResult(result);
}
public void onFailure(Throwable t) {
log.error("Unexpected error", t);
}
})
It seems like Java 8's CompletableFuture
is meant to handle more or less the same use case. Naively, I could start to translate the above example as:
似乎 Java 8CompletableFuture
旨在处理或多或少相同的用例。天真地,我可以开始将上面的例子翻译为:
CompletableFuture<String> future = CompletableFuture<String>.supplyAsync(...)
.thenAccept(this::handleResult)
.exceptionally((t) -> log.error("Unexpected error", t));
This is certainly less verbose than the ListenableFuture
version and looks very promising.
这肯定没有ListenableFuture
版本那么冗长,看起来非常有前途。
However, it doesn't compile, because exceptionally()
doesn't take a Consumer<Throwable>
, it takes a Function<Throwable, ? extends T>
-- in this case, a Function<Throwable, ? extends String>
.
但是,它不会编译,因为exceptionally()
它不需要 a Consumer<Throwable>
,它需要 a Function<Throwable, ? extends T>
-- 在这种情况下, a Function<Throwable, ? extends String>
。
This means that I can't just log the error, I have to come up with a String
value to return in the error case, and there is no meaningful String
value to return in the error case. I can return null
, just to get the code to compile:
这意味着我不能只记录错误,我必须想出一个String
值在错误情况下返回,而在错误情况下没有有意义的String
值返回。我可以返回null
,只是为了让代码编译:
.exceptionally((t) -> {
log.error("Unexpected error", t);
return null; // hope this is ignored
});
But this is starting to get verbose again, and beyond verbosity, I don't like having that null
floating around -- it suggests that someone might try to retrieve or capture that value, and that at some point much later I might have an unexpected NullPointerException
.
但这又开始变得冗长了,除了冗长之外,我不喜欢null
让它四处飘荡——这表明有人可能会尝试检索或捕获该值,而在很久以后的某个时刻,我可能会遇到一个意想不到的NullPointerException
.
If exceptionally()
took a Function<Throwable, Supplier<T>>
I could at least do something like this --
如果exceptionally()
拿了,Function<Throwable, Supplier<T>>
我至少可以做这样的事情——
.exceptionally((t) -> {
log.error("Unexpected error", t);
return () -> {
throw new IllegalStateException("why are you invoking this?");
}
});
-- but it doesn't.
——但事实并非如此。
What's the right thing to do when exceptionally()
should never produce a valid value? Is there something else I can do with CompletableFuture
, or something else in the new Java 8 libraries, that better supports this use case?
当exceptionally()
永远不应该产生有效值时,正确的做法是什么?有什么我可以做的CompletableFuture
,或者新的 Java 8 库中的其他东西,可以更好地支持这个用例吗?
采纳答案by acelent
A correct corresponding transformation with CompletableFuture
is:
一个正确的对应变换CompletableFuture
是:
CompletableFuture<String> future = CompletableFuture.supplyAsync(...);
future.thenAccept(this::handleResult);
future.exceptionally(t -> {
log.error("Unexpected error", t);
return null;
});
Another way:
其他方式:
CompletableFuture<String> future = CompletableFuture.supplyAsync(...);
future
.whenComplete((r, t) -> {
if (t != null) {
log.error("Unexpected error", t);
}
else {
this.handleResult(r);
}
});
The interesting part here is that you were chaining futures in your examples. The seemingly fluent syntax is actually chaining futures, but it seems you don't want that here.
这里有趣的部分是您在示例中链接了期货。看似流畅的语法实际上是链接期货,但似乎您不想要这里。
The future returned by whenComplete
might be interesting if you want to return a future that processes something with an internal future's outcome. It preserves the current future's exception, if any. However, if the future completed normally and the continuation throws, it'll complete exceptionally with the thrown exception.
通过返回的未来whenComplete
,如果你想返回一个未来可能是有趣的是过程的东西与内部未来的结果。它保留当前未来的异常,如果有的话。但是,如果future 正常完成并且continuation 抛出,它将异常完成并抛出异常。
The difference is that anything that happens after future
completes will happen before the next continuation. Using exceptionally
and thenAccept
is equivalent if you're the future
's end-user, but if you're providing a future back to a caller, either one will process without a completion notification (as if in the background, if you may), most probably the exceptionally
continuation since you'll probably want the exception to cascade on further continuations.
不同之处在于,在future
完成之后发生的任何事情都会在下一个延续之前发生。如果您是最终用户,则使用exceptionally
andthenAccept
是等效的future
,但是如果您向调用者提供未来返回,则任何一个都将在没有完成通知的情况下进行处理(如果可以的话,就像在后台一样),很可能的exceptionally
,因为你延续可能会想例外级联的进一步延续。
回答by Ruslan Stelmachenko
Note, that exceptionally(Function<Throwable,? extends T> fn)
also returns CompletableFuture<T>
. So you can chain futher.
请注意,这exceptionally(Function<Throwable,? extends T> fn)
也会返回CompletableFuture<T>
. 所以你可以链接得更远。
The return value of Function<Throwable,? extends T>
is meant to produce fallback result for next chained methods. So you can for example get the value from Cache if it is unavailable from DB.
的返回值Function<Throwable,? extends T>
旨在为下一个链接方法产生回退结果。因此,例如,如果从 DB 中不可用,则可以从 Cache 中获取该值。
CompletableFuture<String> future = CompletableFuture<String>.supplyAsync(/*get from DB*/)
.exceptionally((t) -> {
log.error("Unexpected error", t);
return "Fallback value from cache";
})
.thenAccept(this::handleResult);
If exceptionally
would accept Supplier<T>
instead of function, then how it could return a CompletableFuture<String>
for chaining futher?
如果exceptionally
将接受Supplier<T>
而不是函数,那么它如何返回 aCompletableFuture<String>
以进一步链接?
I think you want a variant of exceptionally
which would return void
. But unfortunately, no, there is no such variant.
我认为你想要一个exceptionally
会返回的变体void
。但不幸的是,不,没有这样的变体。
So, in your case you can safely return any value from this fallback function, if you not return this future
object and not use it futher in your code (so it can't be chained futher). Better not even assign it to a variable.
因此,在您的情况下,您可以安全地从此回退函数返回任何值,如果您不返回此future
对象并且不在您的代码中进一步使用它(因此它不能被进一步链接)。最好不要将其分配给变量。
CompletableFuture<String>.supplyAsync(/*get from DB*/)
.thenAccept(this::handleResult)
.exceptionally((t) -> {
log.error("Unexpected error", t);
return null;
});