我曾经有一个可调用的类
class SampleTask implements Callable<Double> {
@Override
public Double call() throws Exception {
return 0d;
}
}
我曾经使用ExecutorService
来提交Callable
。如何更改为使用CompletableFuture.supplyAsync
?
以下代码无法编译
SampleTask task = new SampleTask();
CompletableFuture.supplyAsync(task);
No instance of type of variable U exists so that SampleTask conforms to Supplier
最佳答案
对于您编写的可调用文件,您可以简单地使用 CompletableFuture.supplyAsync(() -> 0d);
.
但是,如果您已有 Callable
,与 CompletableFuture
一起使用由于可调用对象可能会抛出已检查的异常,因此并不是那么简单。
您可以使用临时 Supplier
它捕获异常并重新抛出它,包装在未经检查的异常中,例如
CompletableFuture.supplyAsync(() -> {
try { return callable.call(); }
catch(Exception e) { throw new CompletionException(e); }
})
使用特定类型CompletionException
而不是 RuntimeException
的任意子类型避免得到 CompletionException
包装运行时异常 包装调用 join()
时的实际异常.
不过,当将异常处理程序链接到 CompletableFuture
时,您会注意到包装。 。另外,CompletionException
由 join()
抛出将是在 catch
中创建的一个子句,因此包含某个后台线程的堆栈跟踪,而不是调用 join()
的线程。换句话说,该行为仍然不同于 Supplier
这会引发异常。
使用稍微复杂一点的
public static <R> CompletableFuture<R> callAsync(Callable<R> callable) {
CompletableFuture<R> cf = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
try { cf.complete(callable.call()); }
catch(Throwable ex) { cf.completeExceptionally(ex); }
});
return cf;
}
你会得到一个CompletableFuture
其行为与 supplyAsync
完全相同,没有额外的包装异常类型,即如果您使用
callAsync(task).exceptionally(t -> {
t.printStackTrace();
return 42.0;
})
t
将是 Callable
抛出的确切异常,如果有的话,即使它是一个受检查的异常。另外callAsync(task).join()
会产生 CompletionException
带有 join()
调用者的堆栈跟踪直接包装Callable
抛出的异常在特殊情况下,与 Supplier
完全相同或类似 runAsync
.
关于java - 如何转换代码以使用CompletableFuture?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43764036/