关于JAVA异常链的学习

参考
https://blog.csdn.net/yizhenn/article/details/68946432
https://www.cnblogs.com/haodawang/articles/5939122.html

异常链

  • 常常会再捕获一个异常后跑出另外一个异常,并且希望把异常原始信息保存下来,这被称为异常链。
  • 在JDK1.4以前,程序员必须自己编写代码来保存原始异常信息,
  • 现在所有Throwable的子类子构造器中都可以接受一个cause对象作为参数,这个cause就异常原由,代表着原始异常,即使在当前位置创建并抛出行的异常,也可以通过这个cause追踪到异常最初发生的位置。
  • Throwable类及其所有的子类都提供了带cause参数的构造器,其他的异常类就只有通过initCause()来设置cause了。

代码

public class ExceptionCause {  
    public static void main(String[] args) throws Exception {     
        test1();  
    }  

    private static void test1() throws Exception{  
    try{  
        test2();  
    }catch(NullPointerException ex){  
//1      Exception bussinessEx = new Exception("packag exception");  
//      bussinessEx.initCause(ex);  
//      throw bussinessEx;  
//2     throw new Exception("packag exception", ex);  
//3     throw (Exception)ex.fillInStackTrace().initCause(ex);  
//      ex.printStackTrace();
    }  
    }        
    private static void test2(){  
    test3();  
    }        
    private static void test3(){  
    throw new  NullPointerException("str is null");  
    }  

}  

输出:什么都不输出
NullPointerException被catch处理了
如果

ex.printStackTrace();

这里写图片描述

输出了异常的出现过程

而当我在catch里面再输出一个exception的时候
这里写图片描述
会提示NullPointerException无法调用PrintStackTrace了
代码:

public class ExceptionCause {  
    public static void main(String[] args) throws Exception {  

        test1();  

    }  

    private static void test1() throws Exception{  
    try{  
        test2();  
    }catch(NullPointerException ex){
        throw new Exception("another exception");
//1      Exception bussinessEx = new Exception("packag exception");  
//      bussinessEx.initCause(ex);  
//      throw bussinessEx;  
//2     throw new Exception("packag exception", ex);  
//3     throw (Exception)ex.fillInStackTrace().initCause(ex);  
//      ex.printStackTrace();
    }  
    }  

    private static void test2(){  
    test3();  
    }  

    private static void test3(){  
    throw new  NullPointerException("str is null");  
    }  

}  

输出
这里写图片描述
也就是说NullPointerException的信息被覆盖了,而这对于我们找到原本的Exception很不利
所以我们需要利用一个cause对象作为参数,这个cause就异常原由,代表着原始异常,即使在当前位置创建并抛出行的异常,也可以通过这个cause追踪到异常最初发生的位置。(Throwable类及其所有的子类都提供了带cause参数的构造器,其他的异常类就只有通过initCause()来设置cause了)

回到代码
这里写图片描述
1和2分别通过initCause()和构造器设置cause。
输出结果
这里写图片描述
cause by即为传入的原Exception的信息
3的出发点和1 2 一样,当能否运行通过?答案是不能,参考http://zy19982004.iteye.com/admin/blogs/1974796 throwable 不能是它自己的 cause。还未看懂???

例子2

有的时候我们会用printStackTrace来打印异常栈,有可能我们会在处理异常的时候同时又抛出一个异常。
自定义两个异常

class MyException1 extends Exception{

} 


class MyException2 extends Exception{
    MyException2(Throwable throwable){
        super(throwable);
    }
    MyException2(){
        super();
    }
}

MyException2 调用了父类的构造方法(带参的),目的是为了能够传递一个cause(即throwable)进来。

关于子类父类构造器的问题

接下来定义一个A 类,并在他的f()方法里调用g()方法,然后在f处理g里抛出的异常MyException1的时候再次抛出一个异常MyException2

class A{
    public void f() throws MyException2{
        try {
            g();
        } catch (MyException1 e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            throw new MyException2();
        }
    }
    public void g() throws MyException1{
        throw new MyException1();
    }
}

在catch里我们又抛出了一个MyException2的异常,这里我们先调用了它的无参构造方法

接下来我们在main里跑一下
输出
这里写图片描述

我们可以明显的发现异常栈的内容变少了。这是因为MyException2对MyException1的环境一无所知。

那么如果MyException2 能够持有MyException1的环境信息,这样做起来就十分方便了,并且也形成了一条链,我们也成为异常链

唯一要修改的就是调用MyException2的有参构造函数(并调用父类有参构造),把MyException1当作cause传递进去,这样的话我们就能获取到MyException1的信息了。

class A{
    public void f() throws MyException2{
        try {
            g();
        } catch (MyException1 e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
                        //这里做了修改
            throw new MyException2(e);
        }
    }
    public void g() throws MyException1{
        throw new MyException1();
    }
}

输出
这里写图片描述

Caused by即为通过异常链机制传入的Myexception1的信息,我们可以通过这样的原理来构造异常链,追溯最原始的异常信息~

猜你喜欢

转载自blog.csdn.net/weixin_38719347/article/details/80944057