从 CompletableFuture 抛出异常

新手上路,请多包涵

我有以下代码:

 // How to throw the ServerException?
public void myFunc() throws ServerException{
    // Some code
    CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> {
        try {
            return someObj.someFunc();
        } catch(ServerException ex) {
            // throw ex; gives an error here.
        }
    }));
    // Some code
}

someFunc() 抛出一个 ServerException 。我不想在这里处理这个,而是将异常从 someFunc() myFunc() 调用者。

原文由 ayushgp 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.8k
2 个回答

您的代码表明您稍后将在同一方法中使用异步操作的结果,因此您必须处理 CompletionException 无论如何,一种处理方法是

public void myFunc() throws ServerException {
    // Some code
    CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> {
        try { return someObj.someFunc(); }
        catch(ServerException ex) { throw new CompletionException(ex); }
    });
    // Some code running in parallel to someFunc()

    A resultOfA;
    try {
        resultOfA = a.join();
    }
    catch(CompletionException ex) {
        try {
            throw ex.getCause();
        }
        catch(Error|RuntimeException|ServerException possible) {
            throw possible;
        }
        catch(Throwable impossible) {
            throw new AssertionError(impossible);
        }
    }
    // some code using resultOfA
}

All exceptions thrown inside the asynchronous processing of the Supplier will get wrapped into a CompletionException when calling join , except the ServerException we have already包裹在 CompletionException 中。

当我们重新抛出 CompletionException 的原因时,我们可能会面临未经检查的异常,即 ServerException ErrorRuntimeException ff3f 的子类 --- 。上面的代码使用 multi-catch 处理所有这些,这将重新抛出它们。由于 getCause() 声明的返回类型是 Throwable ,编译器要求我们处理该类型,尽管我们已经处理了所有可能的类型。直接的解决方案是将这个实际上不可能的 throwable 包裹在 AssertionError 中。

或者,我们可以为自定义异常使用替代结果 future:

 public void myFunc() throws ServerException {
    // Some code
    CompletableFuture<ServerException> exception = new CompletableFuture<>();
    CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> {
        try { return someObj.someFunc(); }
        catch(ServerException ex) {
            exception.complete(ex);
            throw new CompletionException(ex);
        }
    });
    // Some code running in parallel to someFunc()

    A resultOfA;
    try {
        resultOfA = a.join();
    }
    catch(CompletionException ex) {
        if(exception.isDone()) throw exception.join();
        throw ex;
    }

    // some code using resultOfA
}

该解决方案将以其包装形式重新抛出所有“意外”throwables,但仅以通过 exception 未来传递的原始形式抛出自定义 ServerException 。请注意,我们必须确保 a 已完成(例如首先调用 join() ),然后再查询 exception 条件-

原文由 Holger 发布,翻译遵循 CC BY-SA 3.0 许可协议

对于那些使用 completableFuture 寻找其他异常处理方法的人

下面是几种处理 Parsing Error to Integer 的方法:

1. 使用 handle 方法- 这使您能够在异常时提供默认值

CompletableFuture correctHandler = CompletableFuture.supplyAsync(() -> "A")
            .thenApply(Integer::parseInt)
            .handle((result, ex) -> {
                if (null != ex) {
                    ex.printStackTrace();
                    return 0;
                } else {
                    System.out.println("HANDLING " + result);
                    return result;
                }
            })
            .thenAcceptAsync(s -> {
                System.out.println("CORRECT: " + s);
            });

2. 使用 exceptionally 方法- 类似于 handle 但不那么冗长

CompletableFuture parser = CompletableFuture.supplyAsync(() -> "1")
                .thenApply(Integer::parseInt)
                .exceptionally(t -> {
                    t.printStackTrace();
                    return 0;
                }).thenAcceptAsync(s -> System.out.println("CORRECT value: " + s));

3. 使用 whenComplete 方法- 使用此方法将停止其轨道上的方法并且不执行下一个 thenAcceptAsync

 CompletableFuture correctHandler2 = CompletableFuture.supplyAsync(() -> "A")
                .thenApply(Integer::parseInt)
                .whenComplete((result, ex) -> {
                    if (null != ex) {
                        ex.printStackTrace();
                    }
                })
                .thenAcceptAsync(s -> {
                    System.out.println("When Complete: " + s);
                });

4. 通过 completeExceptionally 传播异常

public static CompletableFuture<Integer> converter(String convertMe) {
        CompletableFuture<Integer> future = new CompletableFuture<>();
        try {
            future.complete(Integer.parseInt(convertMe));
        } catch (Exception ex) {
            future.completeExceptionally(ex);
        }
        return future;
    }

原文由 mel3kings 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题