一、简要介绍
Java堆栈跟踪元素分析在异常与调试中很常见,特别是当你的程序有异常抛出的时候,打印出来的一系列堆栈信息,就是堆栈跟踪元素分析的结果。接下来是一些堆栈跟踪元素分析的学习笔记(JAVA核心技术|上卷|11.2.4)与自己理解体会。堆栈跟踪(stack trace)是一个方法调用过程的列表,它包含程序执行过程中方法调用特定位置。注意,堆栈只是跟踪抛出异常的语句,而不必跟踪错误的根源。 Java中Error类以及Exception类都是Throwable类的子类。所以一切都可以用Throwable类来讨论。可以通过Throwable对象调用getStackTrace方法获得一个StackTraceElement对象的数组,然后对这个对象进行分析。接下来一一分析。 ## 二、Throwable类
Throwable类是Error类和Exception类的超类。其中的getStackTrace方法可以获得StackTraceElement(见第三部分)对象的数组,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Throwable(String message, Throwable cause) Throwable initCause(Throwable cause) Throwable getCause() StackTraceElement[] getStackTrace() Throwable t = new Throwable(); StackTraceElement[] frames = t.getStackTrace(); for (StackTraceElement stackTraceElement : frames) { }
|
获取到stackTraceElement对象数组后就可以对其中的元素进行分析,接下来看看stackTraceElement类。
三、stackTraceElement类
stackTraceElement类含有获取文件名和当前执行的代码的行号的方法、获取类名的方法和获取方法名的方法等。在JDK5.0中,增加了静态方法Thread.getAllStackTrace方法用于获取所有线程的堆栈跟踪。以下是stacktraceElement类的常见方法:
1 2 3 4 5 6 7 8 9 10
| String getFileName() int getLineNumber() String getClassName() String getMethodName() boolean isNativeMethod()
|
四、例子代码与分析
跟踪递归阶乘方法的堆栈信息打印情况,见以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class StackTraceDemo { public static int factorial(int n){ System.out.println("factorial(" + n + "):"); Throwable t = new Throwable(); StackTraceElement[] frames = t.getStackTrace(); for (StackTraceElement stackTraceElement : frames) { System.out.println(stackTraceElement); } int r; if (n == 1) { r = 1; }else { r = n * factorial(n - 1); } System.out.println("return " + r); return r; } public static void main(String args[]){ Scanner in = new Scanner(System.in); System.out.print("Enter n: "); int n = in.nextInt(); factorial(n); in.close(); } }
|
计算factorial(3),结果如下:
分析:输入3后,开始计算3的阶乘,每计算一次阶乘打印出当前计算的阶乘的堆栈跟踪信息,包括源代码文件名、源码所在行数以及所经历的类名、方法名。
五、封装使用
下面是封装一个测试流程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class StackTraceDemo { private static Trace trace; public static void main(String args[]){ trace = new Trace(); new StackTraceDemo().traceTest(); } private void traceTest(){ trace.methodStart(); trace.methodToString("is a string"); trace.methodEnd(); } } class Trace{ public void methodStart(){ StackTraceElement stackTraceElement = (new Exception()).getStackTrace()[1]; System.out.print("[" + stackTraceElement.toString() + "]--methodStart" + "n"); } public void methodEnd(){ StackTraceElement stackTraceElement = (new Exception()).getStackTrace()[1]; System.out.print("[" + stackTraceElement.toString() + "]--methodEnd" + "n"); } public void methodToString(String string){ StackTraceElement stackTraceElement = (new Exception()).getStackTrace()[1]; System.out.print("[" + stackTraceElement.toString() + "]--methodToString--" + string + "n"); } }
|
结果:
以后,在程序的调试过程中,可以利用stackTraceElement类对需要的方法进行测试以查看程序的流程。