从CompletableFuture捕获未捕获的异常



我正试图捕获像CompletableFuture.runAsync(() -> {throw new RuntimeException();}); 这样的期货的未捕获异常

我的目标是,当开发人员忘记处理这些异常时,不要让它们沉默。

  • 调用get()join()和try/catch异常不是一个选项,因为它对于代码库中future的所有用法都不是全局的
  • 出于同样的原因,添加.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似乎忽略了它的UncaughtException处理程序,甚至忽略了ForkJoinWorkerThreadFactory,因为我也试图定义

Version1:一切正常,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在后台执行其任务(使用Executor(并处理其任务引发的任何异常,以便通过isCompletedExceptionally等方法报告任务的状态,因此不存在未捕获的异常。

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

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

更新:

由于您不想等待异常,因此可以使用exceptionally或exceptionalyAsync来响应任务引发的任何异常:

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

相关内容

  • 没有找到相关文章

最新更新