繁体   English   中英

从 CompletableFuture 捕获未捕获的异常

[英]Catching uncaught exceptions from 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 似乎忽略了它的 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!");
        }
    }

Output:

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!");
        }
    }

Output:

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");

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM