• 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了。


    博主简介:佘焕敏(shé),洋名 Billy Sir。
    关注编程基础技术,并致力于研究软件的自动化生成。 对编程规范化、面向对象的极致使用也有着浓厚的兴趣。 同时非常希望能够写程序到65岁。
    只有工匠精神,才能把常人觉得单调乏味的代码,当作作品雕刻成艺术品。
  • 相关阅读:
    Luogu 1080 【NOIP2012】国王游戏 (贪心,高精度)
    Luogu 1314 【NOIP2011】聪明的质检员 (二分)
    Luogu 1315 【NOIP2011】观光公交 (贪心)
    Luogu 1312 【NOIP2011】玛雅游戏 (搜索)
    Luogu 1525 【NOIP2010】关押罪犯 (贪心,并查集)
    Luogu 1514 引水入城 (搜索,动态规划)
    UVA 1394 And Then There Was One / Gym 101415A And Then There Was One / UVAlive 3882 And Then There Was One / POJ 3517 And Then There Was One / Aizu 1275 And Then There Was One (动态规划,思维题)
    Luogu 1437 [HNOI2004]敲砖块 (动态规划)
    Luogu 1941 【NOIP2014】飞扬的小鸟 (动态规划)
    HDU 1176 免费馅饼 (动态规划)
  • 原文地址:https://www.cnblogs.com/BillySir/p/14829978.html
Copyright © 2020-2023  润新知