Java异常的栈轨迹(Stack Trace)
3、fillInStackTrace()
我们在前面也提到了这个方法。要说清楚这个方法,首先要讲一下捕获异常之后重新抛出的问题。在catch代码块中捕获到异常,打印栈轨迹,又重新throw出去。在上一级的方法调用中,再捕获这个异常并且打印出栈轨迹信息。这两个栈轨迹信息会一样吗?我们看一下代码:
public class TestPrintStackTrace {public static void f() throws Exception{
throw new Exception("出问题啦!");
}
public static void g() throws Exception{
try {
f();
}catch(Exception e) {
e.printStackTrace();
throw e;
}
}
public static void main(String[] args) {
try {
g();
}catch(Exception e) {
e.printStackTrace();
}
}
在main方法中捕获的异常,是在g()方法中抛出的,按理说这两个打印栈轨迹的信息应该不同,第二次打印的信息应该没有关于f的信息。但是事实上,两次打印栈轨迹信息是一样的。输出结果如下:
java.lang.Exception: 出问题啦!at TestPrintStackTrace.f(TestPrintStackTrace.java:3)
at TestPrintStackTrace.g(TestPrintStackTrace.java:7)
at TestPrintStackTrace.main(TestPrintStackTrace.java:16)
java.lang.Exception: 出问题啦!
at TestPrintStackTrace.f(TestPrintStackTrace.java:3)
at TestPrintStackTrace.g(TestPrintStackTrace.java:7)
at TestPrintStackTrace.main(TestPrintStackTrace.java:16)
也就是说,捕获到异常又立即抛出,在上级方法调用中再次捕获这个异常,打印的栈轨迹信息是一样的。原因在于没有将当前线程当前状态下的轨迹栈的状态保存进Throwabe中。现在我们引入fillInStackTrace()方法。这个方法刚好做的就是这样的保存工作。我们看一下这个方法的原型:
public Throwable fillInStackTrace()这个方法是有返回值的。返回的是保存了当前栈轨迹信息的Throwable对象。我们看看使用fillInStackTrace()方法处理后,打印的栈轨迹信息有什么不同,代码如下:
public class TestPrintStackTrace {public static void f() throws Exception{
throw new Exception("出问题啦!");
}
public static void g() throws Exception{
try {
f();
}catch(Exception e) {
e.printStackTrace();
//不要忘了强制类型转换
throw (Exception)e.fillInStackTrace();
}
}
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:7)
at TestPrintStackTrace.main(TestPrintStackTrace.java:17)
java.lang.Exception: 出问题啦!
at TestPrintStackTrace.g(TestPrintStackTrace.java:11)
at TestPrintStackTrace.main(TestPrintStackTrace.java:17)
我们看到,在main方法中打印栈轨迹已经没有了f相关的信息了。
以上就是关于Java栈轨迹的一些我之前没有掌握的内容,记下来备忘。 捕获到异常时,往往需要进行一些处理。比较简单直接的方式就是打印异常栈轨迹Stack Trace。说起栈轨迹,可能很多人和我一样,第一反应就是printStackTrace()方法。其实除了这个方法,还有一些别的内容也是和栈轨迹有关的。
1、printStackTrace()
首先需要明确,这个方法并不是来自于Exception类。Exception类本身除了定义了几个构造器之外,所有的方法都是从其父类继承过来的。而和异常相关的方法都是从java.lang.Throwable类继承过来的。而printStackTrace()就是其中一个。
这个方法会将Throwable对象的栈轨迹信息打印到标准错误输出流上。输出的大体样子如下:
java.lang.NullPointerExceptionat 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)
====================================分割线================================
最新内容请见作者的GitHub页:http://qaseven.github.io/
【Java基础】栈(Stack) & 队列(Queue) 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。
算法与数据结构-栈(Stack)-Java实现 下压栈(FIFO queue),或者说栈(queue),是一种基于先进后出策略的集合模型。只要你留心,就会发现栈这种数据结构在生活中非常常见。
Java编程之LinkedList+Vector+Stack+Queue Vector类 1.java.util包 2.是ArrayList集合的早期版本 (StringBuffer早期 StringBuilder后来) Vector底层也是利用(动态)数组的形式存储 Vector是线程同步的(synchronized) 安全性高 效率低 3.扩容方式与ArrayList不同 默认是扩容2倍 可以通过构造方法创建对象时修改这一机制 4.构造方法 5.常用方法 Stack类 栈 1.java.util包 2.构造方法只有一个无参数 3.除了继承自Vacton类
java集合系列(7)Stack 这篇文章开始介绍Stack。从名字看他就是一个stack,因此具有数据结构中栈的一般特性(后进先出),平时用起来相对较多一点,但是也是非常简单。这篇文章我们将从源码的角度来分析一下Stack。
Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理 本文非常详尽地介绍了Java中的三个集合类ArrayList,Vector与Stack 《Java集合详解系列》是我在完成夯实Java基础篇的系列博客后准备开始写的新系列。 这些文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下Star、fork哈 文章首发于我的个人博客: www.how2playlife.com //一般讨论集合类无非就是。
相关文章
- Java检查异常和非检查异常,运行时异常和非运行时异常的区别
- java.lang.ClassNotFoundException: org.codehaus.jackson.JsonProcessingException 异常解决方案
- java:stack栈: Stack 类表示后进先出(LIFO)的对象堆栈
- Java反射异常:java.lang.NoSuchFieldException
- Java虚拟机详解02----JVM内存结构
- JAVA学习(五):Java面向对象编程基础
- JAVA 【引用类型】和【对象类型】在【继承】中的异同
- Java实现 LeetCode 437 路径总和 III(三)
- Java实现运动员分组
- Java实现 蓝桥杯VIP 算法提高 去注释
- Java实现 蓝桥杯VIP 算法提高 3000米排名预测
- Java实现 蓝桥杯 算法训练 最大最小公倍数
- (Java实现) 洛谷 P1051 谁拿了最多奖学金
- Java监控工具介绍,VisualVm ,JProfiler,Perfino,Yourkit,Perf4J,JProbe,Java微基准测试
- java 11 标准Java异步HTTP客户端
- Java -- JDBC 学习--事务
- 【JAVA】java中char类型数组用数组名打印结果不是地址值而是数组内容
- 【JAVA】java中split以"." 、""、“|”分隔字符串
- 【JAVA】java编译错误:编码UTF8/GBK的不可映射字符
- 【JAVA】 03-Java中的异常和包的使用
- Java使用LdAP获取AD域用户
- 【JAVA】基于MVC架构Java技术荟萃案例演练
- 【JAVA】java编译错误:编码UTF8/GBK的不可映射字符
- 【译】11条Java异常处理的最佳实践
- 有关java连接数据库的驱动笔记
- Atitit.跨语言异常转换机制 java c# php到js的异常转换
- 【java】Java 包(package)
- 这几种Java异常处理方法,你会吗?
- 解析Java-throw抛出异常详细过程
- 【 华为OD机试 2023】 日志限流(C++ Java JavaScript Python)
- at org.apache.jsp.index_jsp._jspInit(index_jsp.java:23)异常解决
- 【java】Java 封装
- Java刷题面试系列习题(十)