java异常体系
缘由
学习spring源码的时候,看到了NestedRuntimeException,整理一下java异常体系吧。
java异常的分类
如果要熟悉java的异常体系,首先就要从java.lang.Throwable
入手,Throwable
类是java语言中所有错误和异常的超类,无论是java虚拟机还是程序抛出的异常都是Throwable
的子类或者间接子类。
同样我们使用的try{…}catch(…){…}
语句,能够捕捉的也必然是该类或其子类以及间接子类。
对于异常的分类,从不同的角度我们可以将其划分出来不同的类别。
按照UML进行分类
如果按照异常体系的代码涉及上来看,我们可以将异常分为两大家族,Error家族和Exception家族。
Error
其中Error家族比较暴躁,他们是严重问题的代名词,当Error家族的成员出现的时候,往往也就意味着底层资源出现了问题,比如硬件问题,资源问题等,所以在正常的场景下,程序员不应该捕捉或者处理他们,因为对于Error家族的异常,一般我们就算捕获了,也做不了什么。
但是,凡事都有例外,Error家族里面有一个比较特殊的成员
ThreadDeath
,它代表的意义没有Error家族中的其他成员那么严重,算是一个比较正常的错误,
ThreadDeath
异常的触发条件很简单,当我们调用Thread的stop()方法的时候,对应的线程就会抛出ThreadDeath
错误。
对于这个错误我们可以捕捉他,进行一些操作,但是我们必须要再次抛出这个错误,因为只有这样,这个线程才会真正的停止。
Exception
Exception家族的异常就比较温和,他通常表示的是合理的应用程序发生的错误,这种错误往往是程序员意料之中的,通常我们都会捕获Exception家族的异常,并进行处理。
Exception家族的异常往往也是我们主要接触的异常,比如空指针,角标越界之类的异常。
按照异常发现时期分类
对于异常的分类,出于编译时期就能够检查出异常的目的,我们可以把异常分为两类,检查异常和非检查异常。 两者的分类按照下列规则:
Throwable
家族中除RuntimeException
系列和Error
系列之外的所有异常都认为是编译异常,也就是检查异常。
这个分类其实很符合事实逻辑,关于Error家族的错误,他们通常是底层JVM发生了错误,这种错误一旦发生,往往是程序员不可控制的,Error级别的错误很少出现,因此程序员可以减少关注Error级别的错误。
而RuntimeException系列的错误,就和他的名称一样,往往代表着运行时发生的错误,在编译期间往往很难发现。
StackTraceElement
当我们的java程序报错时,程序往往会给我们提供比较详细的错误堆栈信息,来方便我们排查处理问题,而这个堆栈信息则是由一个我们虽然经常接触但却不太熟悉的类组成的——StackTraceElement
。
StackTraceElement
表示堆栈跟踪数据中的一个元素,他本身代表着一个堆栈帧。
我们使用的JVM是一个堆栈虚拟机,他会为每个线程都开辟一个堆栈空间,这个堆栈空间就像一个个小抽屉一样,线程中的代码就执行在这个小抽屉里,在小抽屉上面还有一个标签,这个标签记录了当前线程的状态,而这个标签就是堆栈帧。
StackTraceElement
提供了四个属性来记录所需的堆栈数据:
字段 | 描述 |
---|---|
declaringClass | 方法调用者的类名 |
methodName | 方法名 |
fileName | 文件名 |
lineNumber | 行号 |
并且该类定制Object的hashCode,equals,toString方法。 |
Throwable
说了这么多异常相关的内容,最后总结的时候还是要回到Throwable
类上面,通过前面的内容我们已经能够确定一个概念:
Throwable
是所有异常的超级父类了,在java中的异常必然会是该类或其衍生类。
在确定该概念之后,我们再去观察Throwable
的构造方法,会发现所有的构造方法都必然会调用一个叫做fillInStackTrace
的方法,在fillInStackTrace
方法中会调用一个本地方法来填充异常堆栈集合的数据。
这里涉及了JVM执行代码时,遇到异常的方法退出方式。简单的来说就是: JVM在执行过程中,发现了代码中出现异常,且该异常没有在方法体中处理掉,那么他就会退出当前方法的执行,然后返回调用方法中继续抛出这个异常,周而复始,直到有一个方法处理了这个异常,如果一直都没有方法处理该异常就会导致JVM宕掉。
在这个周而复始往调用方抛出异常的过程中,
Throwable
的fillInStackTrace(int dummy)方法就会详细记录相应堆栈中的数据,从而形成一个完整的堆栈信息表。
参考资料
深入理解Java虚拟机笔记---运行时栈帧结构