异常调用栈轨迹 -- 《JAVA编程思想》36

e.printStackTrace() 方法大家都熟悉不过了,可以将异常栈从栈顶开始打印至控制台。

我们也可通过 e.getStackTrace() 获取一个包含异常栈每一帧的数组,数组中的第一个元素为栈顶元素。

下面这个例子展示了可以通过数组返回的 StackTraceElement 对象获取行数、类名、方法名等信息。

public class WhoCalled {

    public static void f() {
        try {
            throw new Exception();
        } catch (Exception e) {
            for (StackTraceElement ste : e.getStackTrace()) {
                System.out.print("line:"+ste.getLineNumber());
                System.out.print("\t"+"className:"+ste.getClassName());
                System.out.print("\t"+"methodName:"+ste.getMethodName());
                System.out.println();
            }
        }
    }

    public  static void g(){
        f();
    }

    public  static void h(){
        f();
    }

    public static void main(String[] args) {
        f();
        System.out.println("-----------------------");
        g();
        System.out.println("-----------------------");
        h();
        System.out.println("-----------------------");
    }

}
line:12	className:mtn.baymax.charpter12.WhoCalled	methodName:f
line:32	className:mtn.baymax.charpter12.WhoCalled	methodName:main
-----------------------
line:12	className:mtn.baymax.charpter12.WhoCalled	methodName:f
line:24	className:mtn.baymax.charpter12.WhoCalled	methodName:g
line:34	className:mtn.baymax.charpter12.WhoCalled	methodName:main
-----------------------
line:12	className:mtn.baymax.charpter12.WhoCalled	methodName:f
line:28	className:mtn.baymax.charpter12.WhoCalled	methodName:h
line:36	className:mtn.baymax.charpter12.WhoCalled	methodName:main
-----------------------

当我们在捕获一个异常后,假设需要再重新向上抛出异常,但是想把异常进行阻断,不想让调用者看到之前的调用信息,之后再从当前位置重新抛出,该如何操作呢?

通过 fillInStackTrace() 方法返回的 Throwable 对象(Throwable 是 Exception 的基类),转换成 Exception 再进行抛出,就可实现异常阻断的效果。

下例中的 g() 为正常接力向上抛出异常,而 h() 则用 fillInStackTrace() 将异常阻断后再进行抛出。

从打印结构可以看出,从 h() 抛出的异常栈已看不到 f() 方法的调用信息。

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 mtn.baymax.charpter12.Rethrowing.f(Rethrowing.java:12)
	at mtn.baymax.charpter12.Rethrowing.g(Rethrowing.java:17)
	at mtn.baymax.charpter12.Rethrowing.main(Rethrowing.java:37)
main:printStackTrace()
java.lang.Exception: thrown from f()
	at mtn.baymax.charpter12.Rethrowing.f(Rethrowing.java:12)
	at mtn.baymax.charpter12.Rethrowing.g(Rethrowing.java:17)
	at mtn.baymax.charpter12.Rethrowing.main(Rethrowing.java:37)
originating the exception in f()
Inside h(),e.printStackTrace()
java.lang.Exception: thrown from f()
	at mtn.baymax.charpter12.Rethrowing.f(Rethrowing.java:12)
	at mtn.baymax.charpter12.Rethrowing.h(Rethrowing.java:27)
	at mtn.baymax.charpter12.Rethrowing.main(Rethrowing.java:43)
main:printStackTrace()
java.lang.Exception: thrown from f()
	at mtn.baymax.charpter12.Rethrowing.h(Rethrowing.java:31)
	at mtn.baymax.charpter12.Rethrowing.main(Rethrowing.java:43)

Process finished with exit code 0

接下来,我们再来看看另一种情况,在一个位置产生异常后,需要生成新的异常,但同时需要带上初始异常的信息,这时又该如何解决呢?

我们在新的异常生成后,使用 initCause() 将两个异常链接起来。

public class ContactException {

    public static void f() throws Exception {
        throw new Exception();
    }

    public static void g(){
        try {
            f();
        } catch (Exception e) {
            RuntimeException runtimeException = new RuntimeException();
            runtimeException.initCause(e);
            runtimeException.printStackTrace();
        }
    }

    public static void main(String[] args) {
        g();
    }

}

java.lang.RuntimeException
	at mtn.baymax.charpter12.ContactException.g(ContactException.java:18)
	at mtn.baymax.charpter12.ContactException.main(ContactException.java:25)
Caused by: java.lang.Exception
	at mtn.baymax.charpter12.ContactException.f(ContactException.java:11)
	at mtn.baymax.charpter12.ContactException.g(ContactException.java:16)
	... 1 more

本次分享至此结束,希望本文对你有所帮助,若能点亮下方的点赞按钮,在下感激不尽,谢谢您的【精神支持】。

若有任何疑问,也欢迎与我交流,若存在不足之处,也欢迎各位指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BaymaxCS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值