有时候希望把刚捕获的异常重新抛出,尤其是在使用Exception捕获所有异常的时候。既然已经得到了对当前异常对象的引用,可以直接把它重新抛出:
catch(Exception e){
System.out.println("an exception was thrown");
throw e;
}
重新抛出异常会把异常抛给上一级环境中的异常处理程序,同一个try块的后续catch子句将会被忽略。此外,异常对象的所有信息都得以保持,所以高一级环境中捕获此异常的处理程序可以从这个异常对象中得到所有信息。
如果只是把当前异常对象重新抛出,那么printStackTrace()方法显示的将是原来异常抛出的调用栈信息,而非重新抛出点的信息。要向更新这个信息,可以调用filStackTrace()方法,这将返回一个Throwable对象,它是通过把当前调用栈信息填入原来那个异常对象而建立的,就像这样:
public class Rethrowing {
public static void f() throws Exception {
System.out.println("a_mark");
throw new Exception("b_mark");
}
public static void g() throws Exception {
try {
f();
} catch (Exception e) {
System.out.println("c_mark");
e.printStackTrace(System.out);
throw e;
}
}
public static void h() throws Exception {
try {
f();
} catch (Exception e) {
System.out.println("d_mark");
e.printStackTrace(System.out);
throw (Exception) e.fillInStackTrace();
}
}
public static void main(String[] args) {
try {
g();
} catch (Exception e) {
System.out.println("e_mark");
e.printStackTrace(System.out);
}
System.out.println("
-------------between line--------------------
");
try {
h();
} catch (Exception e) {
System.out.println("f_mark");
e.printStackTrace(System.out);
}
}
}
/*输出如下:
a_mark
c_mark
java.lang.Exception: b_mark
at testThread.Rethrowing.f(Rethrowing.java:7)
at testThread.Rethrowing.g(Rethrowing.java:12)
at testThread.Rethrowing.main(Rethrowing.java:32)
e_mark
java.lang.Exception: b_mark
at testThread.Rethrowing.f(Rethrowing.java:7)
at testThread.Rethrowing.g(Rethrowing.java:12)
at testThread.Rethrowing.main(Rethrowing.java:32)
-------------between line--------------------
a_mark
d_mark
java.lang.Exception: b_mark
at testThread.Rethrowing.f(Rethrowing.java:7)
at testThread.Rethrowing.h(Rethrowing.java:22)
at testThread.Rethrowing.main(Rethrowing.java:41)
f_mark
java.lang.Exception: b_mark
at testThread.Rethrowing.h(Rethrowing.java:26)
at testThread.Rethrowing.main(Rethrowing.java:41)
*/
调用filStackTrace()的那一行就成了异常的重新发生地了。
有可能在捕获异常之后抛出另一种异常。这么做的话,得到的效果类似于使用filStackTrace(),有关原来异常发生的信息会丢失,剩下的是与新的抛出点有关的信息:
class OneException extends Exception {
public OneException(String s) {
super(s);
}
}
class TwoException extends Exception {
public TwoException(String s) {
super(s);
}
}
public class RethrowNew {
public static void f() throws OneException {
System.out.println("a_mark");
throw new OneException("thrown from f()");
}
public static void main(String[] args) {
try {
try {
f();
} catch (Exception e) {
System.out.println("b_mark");
e.printStackTrace(System.out);
throw new TwoException("from inner try");
}
} catch (Exception e) {
System.out.println("c_mark");
e.printStackTrace(System.out);
}
}
}
最后那个异常仅知道自己来自 main(),而对 f() 一无所知。
永远不必为清理前一个异常对象而担心,或者说为异常对象的清理而担心。他们都是用 new 在堆上创建的对象,所以gc会自动把他们清理掉。
备:throw 与 throws 之区分
throw 是语句抛出一个异常,该语句用在方法体内,表示抛出异常,由方法体内的语句处理。
throws 是方法可能抛出异常的声明,该语句用在方法声明后面,表示再抛出异常,由该方法的调用者来处理。
////end