我习惯了这种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);
}
})
似乎 Java 8CompletableFuture
旨在处理或多或少相同的用例。天真地,我可以开始将上面的示例翻译为:
CompletableFuture<String> future = CompletableFuture<String>.supplyAsync(...)
.thenAccept(this::handleResult)
.exceptionally((t) -> log.error("Unexpected error", t));
这肯定没有ListenableFuture
版本那么冗长,而且看起来很有希望。
但是,它不会编译,因为exceptionally()
不需要 a Consumer<Throwable>
,它需要 a Function<Throwable, ? extends T>
-- 在这种情况下是 a Function<Throwable, ? extends String>
。
这意味着我不能只记录错误,我必须想出一个String
在错误情况下返回的值,而在错误情况下没有任何有意义的String
值可以返回。我可以 return null
,只是为了让代码编译:
.exceptionally((t) -> {
log.error("Unexpected error", t);
return null; // hope this is ignored
});
但这又开始变得冗长了,而且除了冗长之外,我不喜欢null
让它四处飘荡——这表明有人可能会尝试检索或捕获该值,并且在很久以后的某个时候我可能会有一个意想不到的NullPointerException
.
如果exceptionally()
采取了Function<Throwable, Supplier<T>>
我至少可以做这样的事情 -
.exceptionally((t) -> {
log.error("Unexpected error", t);
return () -> {
throw new IllegalStateException("why are you invoking this?");
}
});
——但事实并非如此。
当exceptionally()
永远不应该产生有效值时,正确的做法是什么?有什么我可以做的CompletableFuture
,或者新的 Java 8 库中的其他东西,可以更好地支持这个用例吗?