Java学习笔记之异常(三)

1.栈轨迹

     上篇博客里说到了异常的一些常用方法,其中有三个方法可以打印异常的调用信息,printStackTrace()所提供的信息可通过getStackTrace()来直接访问,这个方法将返回一个由栈轨迹中的元素构成的数组,其中每个元素代表栈中的一帧,元素0是栈顶元素,并且是调用序列中的最后一个方法调用(这个Throwable被创建和抛出之处),数组中的第一个元素和栈底是调用序列中的第一个方法调用。

class StackTrace 
{
void f() throws Exception{
    throw new Exception("Throw from f()");
}
void g() throws Exception{
    f();
}
public static void main(String[] args) 
{
StackTrace st=new StackTrace();
try{
    st.g();
}catch(Exception e){
    for(StackTraceElement element:e.getStackTrace()){
    System.out.println("Class : "+element.getClassName()+
     " Method : "+element.getMethodName());
}
e.printStackTrace();
}
}
}

Output:

184417_KSuk_1406011.png

可以看到,main方法调用g方法,g方法再调用f方法,这就是异常的栈轨迹。

2.重新抛出异常

   异常是像上面那样根据方法依次调用的,而异常的抛出是抛向其上一个方法交由它处理,上面的代码中,g的异常交由f处理,但是f没有进行捕获,就向上抛出了。有时可以在g中捕获之后,再次抛出,那么这次抛出的异常是由它的上一级来处理,也就是main方法。

void g() throws Exception{
    try{
   f();
}catch(Exception e){
   System.out.println("g() handle exception from f() then throw again");
   throw e;//抛出的异常为从f中捕获的异常,异常信息没有变化
   //throw new Exception("Throw from g()");//抛出的异常为一个新的异常,异常信息与从f中抛出的异常不同
   //throw (Exception)e.fillInStackTrace();//抛出的异常为捕获的异常,但是却更新了异常信息。
   }
}

将1中的代码中的g方法改成上述代码,并将main方法中catch中的foreach注释掉,运行结果如下:

190443_SEg7_1406011.png

因为在g中抛出的异常是从f中捕获的异常,所以异常信息并没有与1中的发生变化,但是将上述代码中的第一行注释段去掉后,也就是在g中抛出了一个新的异常,那么main捕获的自然也是一个新的异常,异常信息自然也不一样了,结果如下:

190625_w3Ok_1406011.png

如果既想重新抛出之前捕获的异常又想更新栈轨迹信息,那么可以使用fillInStackTrace放。将上述代码第二行代码注释去掉后,运行结果如下:

191435_jQ5S_1406011.png

3.异常链

      常常会想要在捕获一个异常后抛出另一个异常,并且希望把原始异常的信息保存下来,这被称为异常链。JDK 1.4之后,所有的Throwable子类在构造器中接受一个cause对象作为参数,这个cause就用来表示原始异常,这样通过把原始异常传递给新的异常,使得即使在当前位置创建并抛出了新的异常,也能通过这个异常追踪到异常最初发生的位置。

        将上述g方法中的异常处理程序抛出的异常代码改为

throw new Exception("Throw from g",e);

运行结果为:

192407_gXEC_1406011.png

可以看到除了新的异常外,还有cause代表的原始异常。

在Throwable子类中,只有三种基本的异常类提供了带cause参数的构造器,它们是Error(用于Java虚拟机报告系统错误)、Exception以及RuntimeException。如果要把其他的异常链接起来,应该使用initCause()方法而不是构造器。

void g() throws IOException{
    try{
   f();
}catch(Exception e){
   System.out.println("g() handle exception from f() then throw again");
   throw (IOException)new IOException("Throw from g").initCause(e);
   }
}

将g方法改成上述代码,抛出IOException,并且使用initCause方法将原始异常作为参数。运行结果如下:

193311_rYfP_1406011.png

4.总结

      1)打印异常栈轨迹可以使用printStackTrace和getStackTrace方法等进行处理。

      2)重新抛出捕获的异常与抛出一个新的异常的区别;既要更新栈调用信息,又想重新抛出之前捕获的异常需要使用fillInStackTrace方法。

      3)异常链是在捕获一个异常后抛出一个新的异常,并将原始异常的信息保存下来。

Error、Exception和RuntimeException可以使用构造器将cause作为参数,而其他的异常则需要使用initCause方法将原始异常作为参数。

转载于:https://my.oschina.net/992257586/blog/351973

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值