允许在 CompletableFuture 中以多种异常类型异常完成

问题描述 投票:0回答:1

我有这个方法

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);
}
java exception completable-future
1个回答
0
投票

在你的代码中

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()
方法抛出自己的异常。

© www.soinside.com 2019 - 2024. All rights reserved.