ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
### [重新抛出异常](https://lingcoder.gitee.io/onjava8/#/book/15-Exceptions?id=%e9%87%8d%e6%96%b0%e6%8a%9b%e5%87%ba%e5%bc%82%e5%b8%b8) 有时希望把刚捕获的异常重新抛出,尤其是在使用 Exception 捕获所有异常的时候。既然已经得到了对当前异常对象的引用,可以直接把它重新抛出: ~~~ catch(Exception e) { System.out.println("An exception was thrown"); throw e; } ~~~ 重抛异常会把异常抛给上一级环境中的异常处理程序,同一个 try 块的后续 catch 子句将被忽略。此外,异常对象的所有信息都得以保持,所以高一级环境中捕获此异常的处理程序可以从这个异常对象中得到所有信息。 如果只是把当前异常对象重新抛出,那么 printStackTrace() 方法显示的将是原来异常抛出点的调用栈信息,而并非重新抛出点的信息。要想更新这个信息,可以调用 fillInStackTrace() 方法,这将返回一个 Throwable 对象,它是通过把当前调用栈信息填入原来那个异常对象而建立的,就像这样: ~~~ // exceptions/Rethrowing.java // Demonstrating fillInStackTrace() public class Rethrowing { public static void f() throws Exception { System.out.println( "originating the exception in f()"); throw new Exception("thrown from f()"); } public static void g() throws Exception { try { f(); } catch(Exception e) { System.out.println( "Inside g(), e.printStackTrace()"); e.printStackTrace(System.out); throw e; } } public static void h() throws Exception { try { f(); } catch(Exception e) { System.out.println( "Inside h(), e.printStackTrace()"); e.printStackTrace(System.out); throw (Exception)e.fillInStackTrace(); } } public static void main(String[] args) { try { g(); } catch(Exception e) { System.out.println("main: printStackTrace()"); e.printStackTrace(System.out); } try { h(); } catch(Exception e) { System.out.println("main: printStackTrace()"); e.printStackTrace(System.out); } } } ~~~ 输出为: ~~~ originating the exception in f() Inside g(), e.printStackTrace() java.lang.Exception: thrown from f() at Rethrowing.f(Rethrowing.java:8) at Rethrowing.g(Rethrowing.java:12) at Rethrowing.main(Rethrowing.java:32) main: printStackTrace() java.lang.Exception: thrown from f() at Rethrowing.f(Rethrowing.java:8) at Rethrowing.g(Rethrowing.java:12) at Rethrowing.main(Rethrowing.java:32) originating the exception in f() Inside h(), e.printStackTrace() java.lang.Exception: thrown from f() at Rethrowing.f(Rethrowing.java:8) at Rethrowing.h(Rethrowing.java:22) at Rethrowing.main(Rethrowing.java:38) main: printStackTrace() java.lang.Exception: thrown from f() at Rethrowing.h(Rethrowing.java:27) at Rethrowing.main(Rethrowing.java:38) ~~~ 调用 fillInStackTrace() 的那一行就成了异常的新发生地了。 有可能在捕获异常之后抛出另一种异常。这么做的话,得到的效果类似于使用 fillInStackTrace(),有关原来异常发生点的信息会丢失,剩下的是与新的抛出点有关的信息: ~~~ // exceptions/RethrowNew.java // Rethrow a different object from the one you caught class OneException extends Exception { OneException(String s) { super(s); } } class TwoException extends Exception { TwoException(String s) { super(s); } } public class RethrowNew { public static void f() throws OneException { System.out.println( "originating the exception in f()"); throw new OneException("thrown from f()"); } public static void main(String[] args) { try { try { f(); } catch(OneException e) { System.out.println( "Caught in inner try, e.printStackTrace()"); e.printStackTrace(System.out); throw new TwoException("from inner try"); } } catch(TwoException e) { System.out.println( "Caught in outer try, e.printStackTrace()"); e.printStackTrace(System.out); } } } ~~~ 输出为: ~~~ originating the exception in f() Caught in inner try, e.printStackTrace() OneException: thrown from f() at RethrowNew.f(RethrowNew.java:16) at RethrowNew.main(RethrowNew.java:21) Caught in outer try, e.printStackTrace() TwoException: from inner try at RethrowNew.main(RethrowNew.java:26) ~~~ 最后那个异常仅知道自己来自 main(),而对 f() 一无所知。 永远不必为清理前一个异常对象而担心,或者说为异常对象的清理而担心。它们都是用 new 在堆上创建的对象,所以垃圾回收器会自动把它们清理掉。