解析Java异常的栈轨迹及其相关方法

一.打印栈轨迹的方法
主动调用Throwable对象的printStackTrace()=printStackTrace(System.err),printStackTrace(PrintStream),printStackTrace(PrintWriter)中的其中一个。
如果一个Exception没有被处理,直接在main方法后面throws,程序退出前将调用异常的printStackTrace()方法,最终是Exception in thread "main" + printStackTrace()

二.栈轨迹
1、printStackTrace()

  首先需要明确,这个方法并不是来自于Exception类。Exception类本身除了定义了几个构造器之外,所有的方法都是从其父类继承过来的。而和异常相关的方法都是从java.lang.Throwable类继承过来的。而printStackTrace()就是其中一个。

  这个方法会将Throwable对象的栈轨迹信息打印到标准错误输出流上。输出的大体样子如下:

java.lang.NullPointerException
     at MyClass.mash(MyClass.java:9)
     at MyClass.crunch(MyClass.java:6)
     at MyClass.main(MyClass.java:3)

  输出的第一行是toString()方法的输出,后面几行的内容都是之前通过fillInStackTrace()方法保存的内容。关于这个方法,我们后面会讲。

  下面看一个例子:

public class TestPrintStackTrace {
  public static void f() throws Exception{
    throw new Exception("出问题啦!");
  }
  public static void g() throws Exception{
    f();
  }
  public static void main(String[] args) {
    try {
      g();
    }catch(Exception e) {
      e.printStackTrace();
    }
  }
}

  这个例子的输出如下:

java.lang.Exception: 出问题啦!
  at TestPrintStackTrace.f(TestPrintStackTrace.java:3)
  at TestPrintStackTrace.g(TestPrintStackTrace.java:6)
  at TestPrintStackTrace.main(TestPrintStackTrace.java:10)

  在这个例子中,在方法f()中抛出异常,方法g()中调用方法f(),在main方法中捕获异常,并且打印栈轨迹信息。因此,输出依次展示了f—>g—>main的过程。

  2、getStackTrace()方法

  这个方法提供了对printStackTrace()方法所打印信息的编程访问。它会返回一个栈轨迹元素的数组。以上面的输出为例,输出的第2-4行每一行的内容对应一个栈轨迹元素。将这些栈轨迹元素保存在一个数组中。每个元素对应栈的一个栈帧。数组的第一个元素保存的是栈顶元素,也就是上面的f。最后一个元素保存的栈底元素。

  下面是一个使用getStackTrace()访问这些轨迹栈元素并打印输出的例子:

public class TestPrintStackTrace {
  public static void f() throws Exception{
    throw new Exception("出问题啦!");
  }
  public static void g() throws Exception{
    f();
  }
  public static void main(String[] args) {
    try {
      g();
    }catch(Exception e) {
      e.printStackTrace();
      System.out.println("------------------------------");
      for(StackTraceElement elem : e.getStackTrace()) {
        System.out.println(elem);
      }
    }
  }
}

  这样的输出和printStackTrace()的输出基本上是一样的,如下:

java.lang.Exception: 出问题啦!
  at TestPrintStackTrace.f(TestPrintStackTrace.java:3)
  at TestPrintStackTrace.g(TestPrintStackTrace.java:6)
  at TestPrintStackTrace.main(TestPrintStackTrace.java:10)
TestPrintStackTrace.f(TestPrintStackTrace.java:3)
TestPrintStackTrace.g(TestPrintStackTrace.java:6)
TestPrintStackTrace.main(TestPrintStackTrace.java:10)

三.fillInStackTrace方法
native fillInStackTrace()方法将返回一个Throwable对象,它是通过把当前调用栈信息填入原来那个异常对象儿建立的,所以返回的还是原来的异常。
调用此方法的那一行将成为异常新的发生地,有关原来异常发生点的信息会丢失。它的效果等价于捕获一个异常后,重新抛出另外一种异常。两者不同的是,fillInStackTrace后的异常还是原来的异常(只是少了栈轨迹而已);而重新抛出一个异常的话,完全跟原异常信息无关了(当然也没有栈轨迹)。

package com.jyz.study.jdk.exception; 

/**
 * 栈轨迹
 * fillInStackTrace
 * @author JoyoungZhang@gmail.com
 *
 */
public class FillInStackTrace { 

  public static void main(String[] args) throws Exception {
  test1();
  } 

  private static void test1() throws Exception{
  try{
    test2();
  }catch(NullPointerException ex){
//1   throw (Exception)ex.fillInStackTrace();
//2   throw new Exception();
  }
  } 

  private static void test2(){
  test3();
  } 

  private static void test3(){
  throw new NullPointerException("str is null");
  } 

}

1和2的异常栈信息均如图:

不同的是this本身的信息,控制台第一行打印的就是this。
1的栈信息

Exception in thread "main" java.lang.NullPointerException: str is null
  at com.jyz.study.jdk.exception.FillInStackTrace.test1(FillInStackTrace.java:20)
  at com.jyz.study.jdk.exception.FillInStackTrace.main(FillInStackTrace.java:13)

2的栈信息

Exception in thread "main" java.lang.Exception
  at com.jyz.study.jdk.exception.FillInStackTrace.test1(FillInStackTrace.java:21)
  at com.jyz.study.jdk.exception.FillInStackTrace.main(FillInStackTrace.java:13) 
(0)

相关推荐

  • java编程之单元测试(Junit)实例分析(附实例源码)

    本文实例讲述了java编程之单元测试.分享给大家供大家参考,具体如下: 完整实例代码代码点击此处本站下载. 在有些时候,我们需要对我们自己编写的代码进行单元测试(好处是,减少后期维护的精力和费用),这是一些最基本的模块测试.当然,在进行单元测试的同时也必然得清楚我们测试的代码的内部逻辑实现,这样在测试的时候才能清楚地将我们希望代码逻辑实现得到的结果和测试实际得到的结果进行验证对比. 废话少说,上代码: 首先创建一个java工程,在工程中创建一个被单元测试的Student数据类,如下: packa

  • Java异常处理中同时有finally和return语句的执行问题

    在Java中当try.finally语句中包含return语句时,执行情况到底是怎样的,finally中的代码是否执行,大家众说纷纭,有的说会执行,有的说不会执行,到底哪种说法正确,现在通过下面的例子加以说明:      第一种情况:try中包含return语句,finally中不包含 public class TestTry { static String s=""; public static void main(String args[]){ s = test1(); Syste

  • 剖析Java中的事件处理与异常处理机制

    一.事件处理 其实,由事件处理这个名字自然就想到MFC中的消息响应机制,就我的体会,它们应该算是南桔北枳的情形吧,我怀疑Java中的事件处理这个"新瓶"应是装的MFC中的消息响应这个"旧酒".     所谓的"事件"即如键盘按键.鼠标点击等这类由动作或什么导致某个状态改变并需要对这个改变作相应响应的这类改变.我们可以将Java中的事件分为按钮.鼠标.键盘.窗口.其它事件这几大类.     事件处理模型  1.   基于继承的事件处理模型(JDK1

  • 总结Java的Struts框架的异常处理方法

    Struts提供了一个更简单的方式来处理未捕获的异常,并将用户重定向到一个专门的错误页面.您可以轻松地Struts配置到不同的异常有不同的错误页面. Struts的异常处理所使用的"exception"拦截容易."exception"拦截器作为默认的栈的一部分,所以不必做任何额外的配置.它可为准备使用的盒.让我们看到了一个简单的Hello World示例进行一些修改在HelloWorldAction.java文件.在这里,我们特意推出了一个空指针异常在我们Hello

  • Java异常处理中的一些特殊情况举例

    只使用try和finally不使用catch的原因和场景 JDK并发工具包中,很多异常处理都使用了如下的结构,如AbstractExecutorService,即只有try和finally没有catch. class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ...

  • Java异常处理之try...catch...语句的使用进阶

    try就像一个网,把try{}里面的代码所抛出的异常都网住,然后把异常交给catch{}里面的代码去处理.最后执行finally之中的代码.无论try中代码有没有异常,也无论catch是否将异常捕获到,finally中的代码都一定会被执行. 虽然 Java 执行时期系统所提供的预设处理器对除错很有用,你通常想要自己处理例外.这样做有两个优点:第一,它让你修正错误.第二,它可以避免程式自动终止.每当错误发生时,如果你的程式就停止而且列印出堆叠追踪,大多数的使用者都会感到很困惑.很幸运,你很容易就能

  • 解析Java中所有错误和异常的父类java.lang.Throwable

    在java语言中,错误类的基类是java.lang.Error,异常类的基类是java.lang.Exception. 1)相同点:java.lang.Error和java.lang.Exception都是java.lang.Throwable的子类,因此java.lang.Error和java.lang.Exception自身及其子类都可以作为throw的使用对象,如:throw new MyError();和throw new MyException();其中,MyError类是java.l

  • Java异常处理实例教程

    1.什么是异常? 首先,让我们来看看下图的例子: 在这个例子中,存在的错误码由除以0的结果.由于除以0而导致异常: ArithmeticException HelloException.java package com.yiibai.tutorial.exception; public class HelloException { public static void main(String[] args) { System.out.println("Three"); // This

  • Java中的异常测试框架JUnit使用上手指南

    JUnit是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression testing framework).Junit测试是程序员测试,即白盒测试.该项目主页:http://www.junit.org/ 使用JUnit时,主要都是通过继承TestCase类别来撰写测试用例,使用testXXX()名称来撰写单元测试. 用JUnit写测试真正所需要的就三件事: 1.  一个import语句引入所有junit.framework.*下的类. 2.  一个exte

  • 浅析Java Web错误/异常处理页面

    发生服务器 500 异常,如果默认方式处理,则是将异常捕获之后跳到 Tomcat 缺省的异常页面,如下图所示. 不论哪个网站都是一样的,所以为了满足自定义的需要,Tomcat 也允许自定义样式的.也就是在 web.xml 文件中配置: <error-page> <error-code>500</error-code> <location>/error.jsp</location> </error-page> 首先说说自带的逻辑.如果某

随机推荐