无论你是使用何种编程语言,在日常的开发过程中,都会不可避免的要处理异常。今天本文将尝试讲解一些JVM如何处理异常问题,希望能够讲清楚这个内部的机制,如果对大家有所启发和帮助,则甚好。
我们在标题中提到了异常,然而这里指的异常并不是单纯的例外,而是更为宽泛的Throwable。只是我们工作中习以为常的将它们(错误地)这样称谓。
关于异常和Throwable的关系简单描述一下
-
<李>异常属于Throwable的子类,Throwable的另一个重要的子类是错误李>
<李>扔可以抛出的都是Throwable和其子类,抓住可捕获的也和是Throwable其子类。
李>
除此之外,但是例外也有一些需要我们再次强调的
-
<李>异常分为两种类型,一种为检查异常,另一种为李>抛出未检测异常
<李>检查异常,比如最常见的IOException,这种异常需要调用处显式处理,要么使用尝试捉捕获,要么再次抛出去。李>
<李>未经检查的异常指的是所有继承自错误(包含自身)或者是RuntimeException(包含自身)的类,这些异常不强制在调用处进行处理。但是也可以尝试抓住处理。李>
本文暂不做检查异常设计的好坏的分析。
提到JVM处理异常的机制,就需要提及异常表,以下称为异常表。我们暂且不急于介绍异常表,先看一个简单的Java处理异常的小例子。
公共静态孔隙simpleTryCatch () { 尝试{ testNPE (); }捕捉(异常e) { e.printStackTrace (); } }
上面的代码是一个很简单的例子,用来捕获处理一个潜在的空指针异常。
当然如果只是看简简单单的代码,我们很难看出什么高深之处,更没有了今天文章要谈论的内容。
所以这里我们需要借助一把神兵利器,它就是程序,一个用来拆解类文件的工具,和javac一样由JDK提供。
然后我们使用javap来分析这段代码(需要先使用javac编译)
//javap - c主要 公共静态孔隙simpleTryCatch (); 代码: 0:invokestatic # 3//方法testNPE: V () 3:转到11 6:astore_0 7:aload_0 8:invokevirtual # 5/java/lang/方法/Exception.printStackTrace: V () 11:返回 异常表: 从目标类型 0 3 6类java/lang/异常
看到上面的代码,应该会有会心一笑,因为终于看到了异常表,也就是我们要研究的异常表。
异常表中包含了一个或多个异常处理者(异常处理程序)的信息,这些信息包含如下
-
<李>从可能发生异常的起始点李>
<李>可能发生异常的结束点李>
<李>目标上从和述之前发生异常后的异常处理者的位置李>
<李>类型异常处理者处理的异常的类信息李>
答案是异常发生的时候,当一个异常发生时
1. jvm会在当前出现异常的方法中,查找异常表,是否有合适的处理者来处理
2。如果当前方法异常表不为空,并且异常符合处理者的从和节点,并且类型也匹配,则JVM调用位于目标的调用者来处理。
3。如果上一条未找到合理的处理者,则继续查找异常表中的剩余条目
4。如果当前方法的异常表无法处理,则向上查找(弹栈处理)刚刚调用该方法的调用处,并重复上面的操作。
5。如果所有的栈帧被弹出,仍然没有处理,则抛给当前的线程,线程则会终止。
6。如果当前线程为最后一个非守护线程,且未处理异常,则会导致JVM终止运行。
以上就是JVM处理异常的一些机制。
除了简单的try - catch外,我们还常常和最后做结合使用。比如这样的代码
公共静态孔隙simpleTryCatchFinally () { 尝试{ testNPE (); }捕捉(异常e) { e.printStackTrace (); 最后}{ System.out.println(“最后”); } }
同样我们使用javap分析一下代码
公共静态孔隙simpleTryCatchFinally (); 代码: 0:invokestatic # 3//方法testNPE: V () 3:getstatic # 6//java/lang/system . out:字段Ljava/io/PrintStream; 6:最后ldc # 7//字符串 8:invokevirtual # 8//java/io/PrintStream.println:方法(Ljava/lang/String;) V 11:转到41 14:astore_0 15:aload_0 16:invokevirtual # 5/java/lang/方法/Exception.printStackTrace: V () 19:getstatic # 6//java/lang/system . out:字段Ljava/io/PrintStream; 22:ldc # 7//字符串最后 24:invokevirtual # 8//java/io/PrintStream.println:方法(Ljava/lang/String;) V 27:转到41 30:astore_1 31:getstatic # 6//java/lang/system . out:字段Ljava/io/PrintStream; 34:ldc # 7//字符串最后 36:invokevirtual # 8//java/io/PrintStream.println:方法(Ljava/lang/String;) V 39:aload_1 40:athrow 41:返回 异常表: 从目标类型 0 3 14类java/lang/例外 0 3 30任何 14日19日30任何JVM如何处理异常深入详解