参考
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的信息,我们可以通过这样的原理来构造异常链,追溯最原始的异常信息~