异常链
除了 try…catch…finally我们还知道些什么,是不是这就是全部了呢?那我们就用案例告诉你,事实不仅仅如此。
先来看一个异常捕获情况
package com.test;
import java.io.IOException;
public class TestB {
void method1() throws Exception {
throw new Exception("exception method1");
}
void method2() throws Exception {
try {
method1();
} catch (IOException e) {
// TODO Auto-generated catch block
Exception c = new Exception();
//异常连
//c.initCause(e);
throw c;
}
}
void method3() throws Exception {
try {
method2();
} catch (Exception e) {
// TODO Auto-generated catch block
Exception c = new Exception();
//异常连
//c.initCause(e);
throw c;
}
}
public static void main(String[] args) {
try {
new TestB().method3();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
OUTPUT :
java.lang.Exception
at com.test.TestB.method3(TestB.java:29)
at com.test.TestB.main(TestB.java:39)
为什么只是打印出来了TestB.java:29而没有打印出exception method1呢?
如果异常信息丢失那么在这个工作空间(workspace)中去寻找最初的异常爆发点就如同大海捞针了。所以异常信息丢失对于开发人员测试自己的代码无疑是一大损失。
这里我们从异常打印信息中完全不知道根本的问题在哪里。特别是当项目越来越大时就更是大海捞针,对修bug的人来说实在耗时又费力。
异常捕获后异常处理到底做了什么
开发人员通过catch(捕获)了异常,并且也处理的异常,但是在处理的过程中又抛出了新的异常
try{
//code
}catch(Exception e)
{
//do something to process exception
throw new Exception();
}
这时java异常处理机制将对捕获的异常信息进行清除,将异常发生地设在新抛出异常的位置(throw new Exception();位置),相当于执行了e.fillInStackTrace()方法。就我举的例子来讲,在查看异常信息时还有可能知道最初的异常发生地在哪里,但是当程序发生嵌套调用或者远程调用时,或者说try{}子句中的代码很多时,对于我们来说寻找最初的异常发生地就是件很难的事了。所以为了解决这样的问题,java异常处理机制提供了一种名为“异常链”的方式。异常链的作用是承接上一次异常信息到当前新抛出的异常中。
异常链
我们将上面的例子稍作修改就可以了
try{
//code
}catch(Exception e)
{
//do something to process exception
throw new Exception(e);//异常链
}
同理我们修改上面的案例如下
new Exception(e);//异常链
package com.test;
import java.io.IOException;
public class TestB {
void method1() throws Exception {
throw new Exception("exception method1");
}
void method2() throws Exception {
try {
method1();
} catch (IOException e) {
// TODO Auto-generated catch block
Exception c = new Exception(e);
//异常连
//c.initCause(e);
throw c;
}
}
void method3() throws Exception {
try {
method2();
} catch (Exception e) {
// TODO Auto-generated catch block
Exception c = new Exception(e);
//异常连
//c.initCause(e);
throw c;
}
}
public static void main(String[] args) {
try {
new TestB().method3();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
OUTPUT :
java.lang.Exception: java.lang.Exception: exception method1
at com.test.TestB.method3(TestB.java:29)
at com.test.TestB.main(TestB.java:39)
Caused by: java.lang.Exception: exception method1
at com.test.TestB.method1(TestB.java:8)
at com.test.TestB.method2(TestB.java:13)
at com.test.TestB.method3(TestB.java:26)
... 1 more
这里直接打印处理“exception method1”
除了这种添加异常链的方式,我们也可以修改原始样例
去掉如下行的所有注释,也会有构造方式异常链同样的效果
//c.initCause(e);
构造方式异常链
将当前的异常作为即将要抛出异常构造方法的一个参数传入,这样在输出异常信息时会自动去检查是否存在原始异常,如果存在则先输出原始异常信息。目前在JDK中这样可以接收原始异常的异常类只有Throwable 、Exception、RuntimeException。所以自定义的异常类要想能够实现异常链的功能必须在继承上述三个类的同时添加一个构造方法能够接收原始异常,并调用父类的对应够方法。
initCause异常链
这个异常链的特性是所有异常均具备的,initCause()方法是从Throwable继承的
参考资料
http://blog.chinaunix.net/uid-26863299-id-3556117.html
http://blog.chinaunix.net/uid-26863299-id-3556117.html