从CompletableFuture捕获未捕获的异常

问题描述

我正在尝试捕获像这样的CompletableFuture.runAsync(() -> {throw new RuntimeException();});

期货中未捕获的异常

我的目标是在开发人员忘记处理这些异常时使这些异常保持沉默。

  • 调用get()join()并尝试/捕获异常不是一种选择,因为它对于代码库中将来的所有用法都不是全局的
  • 出于相同的原因,不能选择添加.exceptionnaly(...)handle(...)。这正是我要防止的事情

这是我的工作(不起作用)

public class Main {
    public static void main(String[] args) throws InterruptedException,ExecutionException {
        System.setProperty("java.util.concurrent.ForkJoinPool.common.exceptionHandler",UncaughtExceptionHandler.class.getName());
        CompletableFuture.runAsync(() -> {
            System.out.println("async");
            throw new RuntimeException();
        });
        System.out.println("Done");
        Thread.sleep(1000);
    }

    static class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
        @Override
        public void uncaughtException(Thread t,Throwable e) {
            System.out.println("Uncaught!");
        }
    }
}

它打印

Done
Async

我想念什么?

编辑

我尝试了这个,但是还是没用

public class Main {
    public static void main(String[] args) throws InterruptedException {
        CompletableFuture.runAsync(() -> {
                    System.out.println("Async");
                    throw new RuntimeException();
                },new ForkJoinPool(
                        Runtime.getRuntime().availableProcessors(),ForkJoinPool.defaultForkJoinWorkerThreadFactory,(t,e) -> System.out.println("Uncaught!"),// UncaughtExceptionHandler
                        false));
        System.out.println("Done");
        Thread.sleep(1000);
    }
}

似乎ForkJoinPool忽略了它的UncaughtExceptionHandler甚至它的ForkJoinWorkerThreadFactory,因为我也尝试定义它。

解决方法

版本1:一切正常,RunAsync方法不会引发任何异常...不会发生任何异常处理...

public static void main(String[] args) throws InterruptedException {
        UncaughtExceptionHandler uncaughtExceptionHandler = new UncaughtExceptionHandler();
        System.setProperty("java.util.concurrent.ForkJoinPool.common.exceptionHandler",UncaughtExceptionHandler.class.getName());
        CompletableFuture.runAsync(() -> {
            System.out.println("async");
        }).exceptionally((ex) -> {
            uncaughtExceptionHandler.uncaughtException(Thread.currentThread(),ex); 
            return null;
        });
        System.out.println("Done");
        Thread.sleep(1000);
    }

    static class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {

        public UncaughtExceptionHandler() { }
        
        public void uncaughtException(Thread t,Throwable e) {
            System.out.println("Uncaught!");
        }
    }

输出:

async
Done

Process finished with exit code 0

版本2:runAsync()引发的异常由异常处理程序完成。

 public static void main(String[] args) throws InterruptedException {
        UncaughtExceptionHandler uncaughtExceptionHandler = new UncaughtExceptionHandler();
        System.setProperty("java.util.concurrent.ForkJoinPool.common.exceptionHandler",UncaughtExceptionHandler.class.getName());
        CompletableFuture.runAsync(() -> {
            throw new RuntimeException("Something went Wrong");
        }).exceptionally((ex) -> {
            uncaughtExceptionHandler.uncaughtException(Thread.currentThread(),ex);
            return null;
        });
        System.out.println("Done");
        Thread.sleep(1000);
    }

    static class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {

        public UncaughtExceptionHandler() { }

        public void uncaughtException(Thread t,Throwable e) {
            System.out.println("Uncaught!");
        }
    }

输出:

Uncaught!
Done

Process finished with exit code 0

两种处理异常的方法:

.exceptionally(ex -> { your_code })-使您有机会从原始Future中产生的错误中恢复。您可以在此处记录异常并返回默认值。 .handle((result,ex) -> { your_code })-表示是否发生异常。也可以用来处理异常

,

您缺少一个事实,即CompletableFuture在后台(使用执行程序)执行其任务并处理其任务引发的任何异常,以便通过isCompletedExceptionally之类的方法报告任务的状态,因此存在没有未捕获的异常。

可以通过调用CompletableFuture的get()方法来传播异常:

CompletableFuture<?> future =
    CompletableFuture.runAsync(() -> {
        System.out.println("async");
        throw new RuntimeException();
    });
future.get();
System.out.println("Done");

更新

由于您不想等待异常,因此可以使用exceptionallyexceptionallyAsync来响应任务抛出的任何异常:

CompletableFuture<?> future =
    CompletableFuture.runAsync(() -> {
        System.out.println("async");
        throw new RuntimeException();
    });
future.exceptionally(e -> {
    System.out.println("Uncaught!");
    return null;
});
System.out.println("Done");

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...