Dav*_*les 17 java completable-future
我习惯了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);
}
})
Run Code Online (Sandbox Code Playgroud)
看起来Java 8的CompletableFuture目的是处理或多或少相同的用例.天真的,我可以开始将上面的例子翻译为:
CompletableFuture<String> future = CompletableFuture<String>.supplyAsync(...)
.thenAccept(this::handleResult)
.exceptionally((t) -> log.error("Unexpected error", t));
Run Code Online (Sandbox Code Playgroud)
这肯定不如ListenableFuture版本那么冗长,看起来非常有前景.
但是,它没有编译,因为exceptionally()不需要a Consumer<Throwable>,它需要一个Function<Throwable, ? extends T>- 在这种情况下,a Function<Throwable, ? extends String>.
这意味着我不能只记录错误,我必须String在错误情况下提出一个返回值,并且在错误情况下没有有意义的String值返回.我可以返回null,只是为了获得编译代码:
.exceptionally((t) -> {
log.error("Unexpected error", t);
return null; // hope this is ignored
});
Run Code Online (Sandbox Code Playgroud)
但是这又开始变得冗长,而且除了冗长之外,我不喜欢null让它漂浮在周围 - 这表明有人可能会尝试检索或捕获该值,并且在某些时候我可能会出现意外情况NullPointerException.
如果exceptionally()花了一个Function<Throwable, Supplier<T>>我至少可以做这样的事情 -
.exceptionally((t) -> {
log.error("Unexpected error", t);
return () -> {
throw new IllegalStateException("why are you invoking this?");
}
});
Run Code Online (Sandbox Code Playgroud)
- 但事实并非如此.
什么是exceptionally()永远不应该产生有效价值的事情?我可以用CompletableFuture新的Java 8库中的其他东西做些什么来更好地支持这个用例吗?
ace*_*ent 12
正确的相应转换CompletableFuture是:
CompletableFuture<String> future = CompletableFuture.supplyAsync(...);
future.thenAccept(this::handleResult);
future.exceptionally(t -> {
log.error("Unexpected error", t);
return null;
});
Run Code Online (Sandbox Code Playgroud)
其他方式:
CompletableFuture<String> future = CompletableFuture.supplyAsync(...);
future
.whenComplete((r, t) -> {
if (t != null) {
log.error("Unexpected error", t);
}
else {
this.handleResult(r);
}
});
Run Code Online (Sandbox Code Playgroud)
这里有趣的部分是你在你的例子中链接了未来.看似流畅的语法实际上是链接未来,但似乎你不想在这里.
通过返回的未来whenComplete,如果你想返回未来处理与内部未来的结果的话会很有趣.如果有的话,它会保留当前未来的例外情况.但是,如果将来正常完成并且继续抛出,则抛出异常将完全异常完成.
不同之处在于future完成后发生的任何事情都会在下一次延续之前发生.如果您是最终用户,则使用exceptionally和thenAccept等效future,但如果您将未来提供给呼叫者,则任何人都将在没有完成通知的情况下处理(如果在后台,如果可能的话),最有可能在exceptionally延续,因为你可能会想例外级联的进一步延续.
请注意,这exceptionally(Function<Throwable,? extends T> fn)也会返回CompletableFuture<T>. 这样你就可以进一步链接。
的返回值Function<Throwable,? extends T>旨在为下一个链接方法生成后备结果。因此,如果数据库无法提供该值,您可以从缓存中获取该值。
CompletableFuture<String> future = CompletableFuture<String>.supplyAsync(/*get from DB*/)
.exceptionally((t) -> {
log.error("Unexpected error", t);
return "Fallback value from cache";
})
.thenAccept(this::handleResult);
Run Code Online (Sandbox Code Playgroud)
如果exceptionally接受Consumer<T>而不是函数,那么它如何返回一个CompletableFuture<String>用于进一步链接?
我想你想要一个exceptionally会返回的变体void。但不幸的是,不,没有这样的变体。
因此,在您的情况下,如果您不返回该future对象并且不在代码中进一步使用它(因此无法进一步链接它),您可以安全地从此后备函数返回任何值。最好甚至不要将其分配给变量。
CompletableFuture<String>.supplyAsync(/*get from DB*/)
.thenAccept(this::handleResult)
.exceptionally((t) -> {
log.error("Unexpected error", t);
return null;
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10885 次 |
| 最近记录: |