Java: 帮助Checked Exception通过Unchecked Exception通道的技术

  最近用到了Java的异步框架,名叫Future。它通常是与λ表达式结合来使用的。λ表达式是通过某类注解(接口)定义 的。但是看了类似java.lang.Runnable.run()这些方法都没有定义throws,也就是意味着它不支持抛出受检异常(checked exception)。

  我采取了一个方案,自己捕获受检异常,并把它保存到一个集合中。在各个异步任务都结束的时候检查这个集合,如果非空则进行回滚操作。这个方案的缺点是,与异步框架结合的不够好。有受检异常发生时,不会自动取消后续的异步任务。

  能不能把所有的受检异常都变成非受检异常(unchecked exception)呢?就是说,在一个受检异常发生时,第一时间就把它变成非受检异常。从而实现整个系统中的受检异常在尽可能小的范围内发生和传播。或许JDK也希望我们这么做,不然为什么这些与Future紧密相关的λ表达式都不支持受检异常呢。鉴于现有的代码以及大量的组件都使用了受检异常。如果都转为非受检异常,势必要改造很多个类,既有工作量也有挑战,暂且不能这么干。

  能不能做一个隧道,帮助受检异常顺利的通过不支持受检异常的通道,并在通过后对其进行恢复。示意图如下。


  经过实验,这个方案是可行的。我封装了一个类来做这件事,代码如下。

public class CheckedExceptionWrapperException extends RuntimeException {

    public CheckedExceptionWrapperException(String message, Throwable ex) {
        super(message, ex);
    }
    
    public static CheckedExceptionWrapperException wrap(String message, Excepton ex) {
        if (ex isinstanceof CheckedExceptionWrapperException) {
            return (CheckedExceptionWrapperException) ex;
        }
        return new CheckedExceptionWrapperException(message, ex);
    }
    
    public static Excepton unwrap(Excepton ex) {
        if (ex isinstanceof CheckedExceptionWrapperException) {
            return ((CheckedExceptionWrapperException) ex).unwrap();
        }
        return ex;
    }
    
    public Excepton unwrap() {
        return this.getInnerExeption();
    }
}

 

用法举例

import java.util.concurrent.CompletableFuture;

task1 = CompletableFuture.runAsyn(() -> {
    try {
        doSomeThing1();
    } catch(Excepton ex) {
        throw CheckedExceptionWrapperException.wrap(ex);
    }
});
task2 = task1.thenRun(() -> {
    try {
        doSomeThing2();
    } catch(Excepton ex) {
        throw CheckedExceptionWrapperException.wrap(ex);
    }
});
task3 = CompletableFuture.runAsyn(() -> {
    try {
        doSomeThing3();
    } catch(Excepton ex) {
        throw CheckedExceptionWrapperException.wrap(ex);
    }
});
task4 = task3.thenRun(() -> {
    try {
        doSomeThing4();
    } catch(Excepton ex) {
        throw CheckedExceptionWrapperException.wrap(ex);
    }
});
try {
    CompletableFuture.all(task2, task4).get();
} catch(Excepton ex) {
    throw CheckedExceptionWrapperException.unwrap(ex);
}

  达到的效果就是无论发生受检异常还是非受检异常,都能够利用异步框架的机制,取消后续任务的执行。能够利用异步框架进行传播,并在需要的时候进行恢复(抛出与捕获),恢复后能得到原始的调用栈。

  实际使用时发现异步框架在捕获到异常时,还会再包装一层它自己的异常,所以我也在这个类中对这一层进行解包装。代码如下。

public class CheckedExceptionWrapperException extends RuntimeException {
    // ...
    public static Excepton unwrap(Excepton ex) {
        if (ex isinstanceof java.util.concurrent.CompletionException) {
            return unwrap(ex.getInnerExeption())
        }
        if (ex isinstanceof CheckedExceptionWrapperException) {
            return ((CheckedExceptionWrapperException) ex).unwrap();
        }
        return ex;
    }
    // ...
}

   我把这项技术称作为异常隧道。这个隧道帮助受检异常通过了原本通不过的通道。有了这个异常隧道,终于可以好好地使用Future了。

posted @ 2021-05-31 09:09  BillySir  阅读(111)  评论(0编辑  收藏  举报