gpt4 book ai didi

java - CompletableFuture#异常地重新抛出已检查的异常

转载 作者:行者123 更新时间:2023-11-30 05:42:08 36 4
gpt4 key购买 nike

假设我想在遇到特定异常时恢复一些值,否则返回带有异常的失败的 future。我期望这样的事情:

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函数会抛出checked异常,我想在链式方法中处理它。我尝试了 return throwable 和 throw throwable ,但都没有编译。 CompletableFuture 是否为这种情况提供任何解决方案?我知道作为 exceptionly 方法参数的 Function 接口(interface)不会抛出任何异常 - 在这种情况下我只想返回已经失败的 future。我想找到使用 Java 8 的解决方案。

最佳答案

在这种情况下,不可能接收已检查的异常,因为前一阶段是基于 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() 的调用者将获得除 CompletionExceptionCancellationException 之外的所有异常无论如何,在 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)

堆栈跟踪略有不同,但对接收/捕获异常的代码没有影响,无论哪种情况,它都是包装 IllegalStateExceptionCompletionException >.

所以回到你的问题的例子,你可以使用

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);
});

关于java - CompletableFuture#异常地重新抛出已检查的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55453961/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com