假设如果我遇到特定的异常,我想以某个值恢复,否则返回带有异常的失败的将来。我希望这样的事情:
[[x[0], x[1] + 's', x[2] + '1'] for x in a]
如果IndexError: list index out of range
函数会抛出一个 checked 异常,我想在链接方法中对其进行处理。我已经尝试过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
,但是都没有编译。 return throwable
可以为这种情况提供任何解决方案吗?我知道throw throwable
方法的参数CompletableFuture
接口不会引发任何异常-在这种情况下,我只想返回已经失败的将来。我想找到一个使用Java 8的解决方案。
答案 0 :(得分:1)
在这种情况下,由于上一阶段基于Supplier
,因此不允许接收已检查的异常。
因此,您可以处理所有未检查的异常,并为应该不可能的可抛出对象引发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()
的调用者都将获得除包裹在CompletionException
中的CancellationException
和CompletionException
之外的所有异常。例如。当我使用
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
因此,我利用CompletionException
不再被包裹这一事实,可以使用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 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)
在堆栈跟踪中稍有不同,但是对接收/捕获异常的代码没有影响,因为在两种情况下,它都是CompletionException
包裹了IllegalStateException
。
所以回到问题的示例,您可以使用
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);
});