我有这个方法
private CompletableFuture<String> createCode(CodeRequest codeRequest) {
return salesCompletableFuture
.supplyAsync(() -> getVoucherCode(salesRequest), forkJoinPool.threadPool())
.exceptionally(ServiceException::handleFutureException);
}
这是handleFutureException:
public static <T> T handleFutureException(Throwable ex) {
if (ex instanceof CompletionException || ex instanceof ExecutionException) {
if (ex.getCause() instanceof ServiceException) {
throw new ServiceException((ServiceException) ex.getCause());
} else {
throw new ServiceException(ex.getCause().getMessage(), ex.getCause());
}
}
else if (ex instanceof ServiceException exception) {
throw new ServiceException(exception);
}
throw new ServiceException(ex.getMessage(), ex);
}
public ServiceException(String message, Throwable cause) {
super(message, cause);
}
}
CompletableFuture 抛出的唯一异常类型是 ServiceException。是否可以以某种方式更改我的代码,使其返回 ServiceWarningException(如果这确实是异常类型和其他所有内容的 ServiceException)?
我在handleFutureException中尝试了以下方法,但这不起作用。
else if (ex instanceof ServiceWarningException exception) {
throw new ServiceWarningException(exception);
}
在你的代码中
if (ex instanceof CompletionException || ex instanceof ExecutionException) {
} else if (ex instanceof ServiceException exception) {
} else if (ex instanceof ServiceWarningException exception) {
}
检查传递给
exceptionally
的异常类型是没有意义的,因为异常将始终是 CompletionException
。
让我们证明一下。
run
类的AsyncSupply
方法是
static final class AsyncSupply<T> extends ForkJoinTask<Void> implements Runnable, AsynchronousCompletionTask {
public void run() {
CompletableFuture<T> d; Supplier<? extends T> f;
if ((d = dep) != null && (f = fn) != null) {
dep = null; fn = null;
if (d.result == null) {
try {
d.completeValue(f.get());
} catch (Throwable ex) {
d.completeThrowable(ex);
}
}
d.postComplete();
}
}
}
这样,如果在调用
getVoucherCode(salesRequest)
方法时抛出异常,它将被捕获并发送到 completeThrowable()
方法,该方法又会调用 encodeThrowable()
将异常包装在 CompletionException
中。
final boolean completeThrowable(Throwable x) {
return RESULT.compareAndSet(this, null, encodeThrowable(x));
}
static AltResult encodeThrowable(Throwable x) {
return new AltResult((x instanceof CompletionException) ? x :
wrapInCompletionException(x));
}
这样,您的
handleFutureException()
处理程序将始终只收到 CompletionException
。
现在让我们考虑一下如果在异常处理程序中抛出异常会发生什么。
uniExceptionally()
方法负责执行handleFutureException()
处理程序中的代码。
final boolean uniExceptionally(Object r, Function<? super Throwable, ? extends T> f, UniExceptionally<T> c) {
Throwable x;
if (result == null) {
try {
if (c != null && !c.claim())
return false;
if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
completeValue(f.apply(x));
else
internalComplete(r);
} catch (Throwable ex) {
completeThrowable(ex);
}
}
return true;
}
如果您在
handleFutureException()
方法中抛出异常,则 uniExceptionally()
方法会捕获它并将其发送到 completeThrowable()
方法,正如我们之前讨论的,该方法再次将您的异常包装在 CompletionException
中。
因此,您永远不能直接从
handleFutureException()
方法抛出自己的异常。