假设我想在收到特定异常时恢复某个值,否则返回失败的未来。我希望是这样的:
public static void main(String[] args) {
CompletableFuture
.supplyAsync(FuturesExample::fetchValue)
.exceptionally(throwable -> {
if (throwable instanceof RuntimeException) {
return "All good";
}
throw throwable; // does not compile
});
}
public static String fetchValue() {
// code that potentially throws an exception
return "value";
}
如果fetchValue
函数会抛出检查过的异常,我想在链式方法中处理它。我尝试过back throwable
和抛出throwable
,但都无法编译。CompletableFuture
是否为这种情况提供了任何解决方案?我知道Function
接口是异常
方法的参数,它不会抛出任何异常——在这种情况下,我只想返回已经失败的未来。我想找到使用Java8的解决方案。
正如霍尔格所写,这通常是不可能的
但是,lombok有一个技巧,它是@SneakyThrows。
public static void main(String[] args) {
CompletableFuture
.supplyAsync(FuturesExample::fetchValue)
.exceptionally(throwable -> {
if (throwable instanceof RuntimeException) {
return "All good";
}
FutureExample.reThrow(throwable);
// maybe a "return null" is necessary here (even when it is not reachable)
});
}
public static String fetchValue() {
// code that potentially throws an exception
return "value";
}
@SneakyThrows // <- threat checked exceptions in method-body as unchecked
public static void reThrow(Throwable throwable) {
throw throwable;
}
在这种情况下,不可能收到已检查的异常,因为前一阶段基于供应商
,不允许抛出已检查的异常。
因此,您可以处理所有未检查的异常并为应该是不可能的throwable引发AssertionError
:
CompletableFuture
.supplyAsync(FuturesExample::fetchValue)
.exceptionally(throwable -> {
if (throwable instanceof RuntimeException) {
return "All good";
}
if(throwable instanceof Error) throw (Error)throwable;
throw new AssertionError(throwable);
});
否则,您可能会认为后续阶段以及 join()
的调用方将获得除“完成异常”
和“取消
异常”之外的所有异常都包装在“完成异常”
中。例如,当我使用
public static void main(String[] args) {
CompletableFuture<String> f = CompletableFuture
.supplyAsync(FuturesExample::fetchValue)
.exceptionally(throwable -> {
if(throwable instanceof RuntimeException) {
throw (RuntimeException)throwable;
}
throw new Error();
});
f.whenComplete((s,t) -> {
if(t != null) {
System.err.println("in whenComplete handler ");
t.printStackTrace();
}
});
System.err.println("calling join()");
f.join();
}
public static String fetchValue() {
throw new IllegalStateException("a test is going on");
}
我明白了
in whenComplete handler
java.util.concurrent.CompletionException: java.lang.IllegalStateException: a test is going on
at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:314)
at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:319)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1702)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1692)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
Caused by: java.lang.IllegalStateException: a test is going on
at FuturesExample.fetchValue(FuturesExample.java:23)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
... 6 more
calling join()
Exception in thread "main" java.util.concurrent.CompletionException: java.lang.IllegalStateException: a test is going on
at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:314)
at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:319)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1702)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1692)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
Caused by: java.lang.IllegalStateException: a test is going on
at FuturesExample.fetchValue(FuturesExample.java:23)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
... 6 more
因此,我可以使用< code>CompletionException来包装任意的throwables,利用< code>CompletionException不会被再次包装的事实。所以如果我用
public static void main(String[] args) {
CompletableFuture<String> f = CompletableFuture
.supplyAsync(FuturesExample::fetchValue)
.exceptionally(throwable -> {
if(throwable instanceof CompletionException)
throwable = throwable.getCause();
System.err.println("wrapping '"+throwable+"' inside exceptionally");
throw new CompletionException(throwable);
});
f.whenComplete((s,t) -> {
if(t != null) {
System.err.println("in whenComplete handler ");
t.printStackTrace();
}
});
System.err.println("calling join()");
f.join();
}
public static String fetchValue() {
throw new IllegalStateException("a test is going on");
}
我明白了
wrapping 'java.lang.IllegalStateException: a test is going on' inside exceptionally
in whenComplete handler
java.util.concurrent.CompletionException: java.lang.IllegalStateException: a test is going on
at FuturesExample.lambda$main$0(FuturesExample.java:12)
at java.base/java.util.concurrent.CompletableFuture.uniExceptionally(CompletableFuture.java:986)
at java.base/java.util.concurrent.CompletableFuture$UniExceptionally.tryFire(CompletableFuture.java:970)
at java.base/java.util.concurrent.CompletableFuture.unipush(CompletableFuture.java:589)
at java.base/java.util.concurrent.CompletableFuture.uniExceptionallyStage(CompletableFuture.java:1002)
at java.base/java.util.concurrent.CompletableFuture.exceptionally(CompletableFuture.java:2307)
at FuturesExample.main(FuturesExample.java:8)
Caused by: java.lang.IllegalStateException: a test is going on
at FuturesExample.fetchValue(FuturesExample.java:24)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1692)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
calling join()
Exception in thread "main" java.util.concurrent.CompletionException: java.lang.IllegalStateException: a test is going on
at FuturesExample.lambda$main$0(FuturesExample.java:12)
at java.base/java.util.concurrent.CompletableFuture.uniExceptionally(CompletableFuture.java:986)
at java.base/java.util.concurrent.CompletableFuture$UniExceptionally.tryFire(CompletableFuture.java:970)
at java.base/java.util.concurrent.CompletableFuture.unipush(CompletableFuture.java:589)
at java.base/java.util.concurrent.CompletableFuture.uniExceptionallyStage(CompletableFuture.java:1002)
at java.base/java.util.concurrent.CompletableFuture.exceptionally(CompletableFuture.java:2307)
at FuturesExample.main(FuturesExample.java:8)
Caused by: java.lang.IllegalStateException: a test is html" target="_blank">going on
at FuturesExample.fetchValue(FuturesExample.java:24)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1692)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
这在堆栈跟踪中略有不同,但对接收/捕获异常的代码没有影响,因为在任何一种情况下,它都是包装IllegalStateException
的CompletionException
。
回到你的问题的例子,你可以使用
CompletableFuture
.supplyAsync(FuturesExample::fetchValue)
.exceptionally(throwable -> {
if (throwable instanceof RuntimeException) { // includes CompletionException
return "All good";
}
throw new CompletionException(throwable);
});
由于CompletionException
是RuntimeException
,因此此代码处理它并避免将CompletionException
包装在另一个CompletionException
中。否则,模式将是
.exceptionally(throwable -> {
if (some condition) {
return some value;
}
throw throwable instanceof CompletionException?
(CompletionException)throwable: new CompletionException(throwable);
});
问题内容: 包含多个有关将检查的异常与混合使用的问题。 虽然一些答案暗示使用其方法会导致难以阅读的用户代码。 我将使用此空间来提供可提高可读性的替代解决方案。 请注意,此问题特定于CompletableFuture。 这使我们能够提供更广泛地不扩展到lambda表达式的解决方案。 问题答案: 给定实用程序类(下面提供),用户可以无缝地抛出检查异常: 由lambda引发的任何异常(是否经过检查)都将
问题内容: 我有以下代码: 抛出一个。我不想在这里处理此问题,但是将异常从抛出给的调用者。 问题答案: 您的代码建议您稍后以相同的方法使用异步操作的结果,因此无论如何都必须进行处理,因此一种处理方法是 在的异步处理中抛出的所有异常都将在调用时包装为一个,除了我们已经包装在一个。 当重新引发的原因时,我们可能会遇到未检查的异常,即or的子类或我们的自定义检查的异常。上面的代码通过多次捕获来处理所有这
使用CompletableFuture这一伟大特性,我想将使用异常的旧异步代码转换为这一新特性。但检查的异常是困扰我的东西。这是我的代码。 方法的签名: 如何处理ComletableFuture中的检查异常?
问题内容: 我有一个关于Java中重新引发异常的非常简单的问题。 这是代码片段: 为什么我们需要在第一个版本中重新抛出,而第二个版本看起来更优雅?可能有什么好处,并且优先选择哪个版本? 问题答案: 你是对的。第二版更好。而且,第一个版本没有任何意义。除了异常的堆栈跟踪为“错误”之外,它的功能相同。 有“重新抛出”异常的原因如下: 如果您之前有事要做。 如果捕获一种类型的异常并抛出另一种类型的异常:
你怎么捕获一个异常,之后在另外一个线程上重新抛出?使用在标准文档18.8.5中描述的异常传递中的方法吧,那将显示标准库的魔力。 exception_ptr current_exception(); 返回一个exception_ptr 变量,它将指向现在正在处理的异常(15.3)或者现在正在处理的异常的副本(拷贝),或者有的时候在当前没有遇到异常的时候,返回值为一个空的exception_ptr变量
抛出异常的行为是否可能抛出不同的异常? 为了抛出异常,必须(可选地)分配新对象,并调用其构造函数(隐式调用fillinstacktrace)。在某些情况下,听起来像addSupressed也被称为。那么如果没有足够的内存会发生什么呢?JVM是否需要预分配内置异常?例如,(1/0)会抛出OutOfMemoryError而不是ArithmeticException吗? 此外,构造函数是一个方法调用,因