使用 CompletableFuture 处理 Java 8 供应商异常 [英] Java 8 Supplier Exception handling with CompletableFuture
问题描述
考虑下面的代码
public class TestCompletableFuture {
BiConsumer<Integer, Throwable> biConsumer = (x,y) -> {
System.out.println(x);
System.out.println(y);
};
public static void main(String args[]) {
TestCompletableFuture testF = new TestCompletableFuture();
testF.start();
}
public void start() {
Supplier<Integer> numberSupplier = new Supplier<Integer>() {
@Override
public Integer get() {
return SupplyNumbers.sendNumbers();
}
};
CompletableFuture<Integer> testFuture = CompletableFuture.supplyAsync(numberSupplier).whenComplete(biConsumer);
}
}
class SupplyNumbers {
public static Integer sendNumbers(){
return 25; // just for working sake its not correct.
}
}
上面的东西工作正常.但是 sendNumbers
也可以在我的情况下抛出一个已检查的异常,例如:
The above thing works fine. However sendNumbers
could also throw a checked exception in my case, like:
class SupplyNumbers {
public static Integer sendNumbers() throws Exception {
return 25; // just for working sake its not correct.
}
}
现在我想在我的 biConsumer
中将这个异常作为 y
处理.这将帮助我处理单个函数 (biConsumer
) 内的结果和异常(如果有).
Now I want to handle this exception as y
in my biConsumer
. This will help me in handling the result as well as exception (if any) inside a single function (biConsumer
).
有什么想法吗?我可以在这里使用 CompletableFuture.exceptionally(fn)
或其他任何东西吗?
Any ideas? Can I use CompletableFuture.exceptionally(fn)
here or anything else?
推荐答案
当您想要处理已检查异常时,使用标准函数式接口的工厂方法没有帮助.当您将捕获异常的代码插入到 lambda 表达式中时,您会遇到问题:catch 子句需要 CompletableFuture
实例来设置异常,而工厂方法需要 Supplier
,鸡和蛋.
The factory methods using the standard functional interfaces aren’t helpful when you want to handle checked exceptions. When you insert code catching the exception into the lambda expression, you have the problem that the catch clause needs the CompletableFuture
instance to set the exception while the factory method needs the Supplier
, chicken-and-egg.
您可以使用类的实例字段来允许在创建后进行更改,但最终,生成的代码并不干净,而且比基于 Executor
的直接解决方案更复杂.CompletableFuture
说:
You could use an instance field of a class to allow mutation after creation, but in the end, the resulting code isn’t clean and more complicated that a straight-forward Executor
-based solution. The documentation of CompletableFuture
says:
- 所有没有显式 Executor 参数的 async 方法都使用
ForkJoinPool.commonPool()
...
所以您知道以下代码将显示 CompletableFuture.supplyAsync(Supplier)
的标准行为,同时直接处理已检查的异常:
So you know the following code will show the standard behavior of CompletableFuture.supplyAsync(Supplier)
while handling checked exceptions straight-forward:
CompletableFuture<Integer> f=new CompletableFuture<>();
ForkJoinPool.commonPool().submit(()-> {
try { f.complete(SupplyNumbers.sendNumbers()); }
catch(Exception ex) { f.completeExceptionally(ex); }
});
文档还说:
... 为了简化监控、调试和跟踪,所有生成的异步任务都是标记接口的实例 CompletableFuture.AsynchronousCompletionTask
.
… To simplify monitoring, debugging, and tracking, all generated asynchronous tasks are instances of the marker interface
CompletableFuture.AsynchronousCompletionTask
.
如果您想遵守此约定以使解决方案的行为更像原始 supplyAsync
方法,请将代码更改为:
If you want to adhere to this convention to make the solution even more behaving like the original supplyAsync
method, change the code to:
CompletableFuture<Integer> f=new CompletableFuture<>();
ForkJoinPool.commonPool().submit(
(Runnable&CompletableFuture.AsynchronousCompletionTask)()-> {
try { f.complete(SupplyNumbers.sendNumbers()); }
catch(Exception ex) { f.completeExceptionally(ex); }
});
这篇关于使用 CompletableFuture 处理 Java 8 供应商异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!