让咱们准备一个函数:架构
而后,反编译他的字节码:jvm
首先咱们介绍异常表:在编译生成的字节码中,每一个方法都附带一个异常表。函数
异常表中的每个条目表明一个异常处理器,而且由 from 指针、to 指针、target 指针以及所捕获的异常类型构成。这些指针的值是字节码索引用以定位字节码。学习
下图就是我特别指出的JVM字节码中的异常表部分。线程
咱们来分析一下这几个语句的执行流程,首先执行:指针
这至关于执行:
cdn
再来:
blog
上图至关于执行
索引
有人问:try去哪了?
get
我立刻就要介绍。此时idiv执行完就有异常了,有异常了先找异常表。
我再贴一下异常表,他是怎么搜索的呢?
当程序触发异常时,Java 虚拟机会从上至下遍历异常表中的全部条目。
当触发异常的字节码的索引值在某个异常表条目的监控范围内,Java 虚拟机会判断所抛出的异常和该条目想要捕获的异常是否匹配。
若是匹配,Java 虚拟机会将控制流转移至该条目 target 指针指向的字节码。
咱们看 ,是第四个索引指向的字节码出了问题,显然,此时应该匹配红线这一条记录,从而跳转到第14个索引的字节码。
咱们看他怎么作的?
new出一个RuntimeException并抛出,它就是
这一句,按照咱们刚才的流程,此时依然须要找到这个RuntimeException在哪一个异常表的条目中
此时匹配到异常表的条目,跳转到字节码索引23
继续抛出RuntimeExcpetion,能够注意到 这实际上对应了
这个语句,因而咱们能够知道,在三个都出现异常的状况下,实际上最终向外抛出的异常是finally里面的异常。
能够看到当31索引处调用athrow语句抛出异常时,此时异常表没有任何一个条目可以匹配该异常,此时怎么办呢?
若是遍历完全部异常表条目,Java 虚拟机仍未匹配到异常处理器,那么它会弹出当前方法对应的 Java 栈帧,而且在调用者中重复上述操做。
在最坏状况下,Java 虚拟机须要遍历当前线程 Java 栈上全部方法的异常表。
事实上分析以上的总体的所有语句你能够发现,jvm层面有真正的finally吗?
没有
如今的作法是,复制 finally 代码块的内容,分别放在 try-catch 代码块全部正常执行路径以及异常执行路径的出口中。不管是否出现异常,确保必定会执行finally语句。
刚才catch出了异常,依然执行finally语句就能够发现这一点。至于其余路径,你们能够自行验证。我就在这里抛砖引玉了。
至于为何2-6发生任何异常都跳转到23?你们能够本身想一下这个问题。
我就提示一点 2-6 target为14的条目表明的catch是不能捕获全部异常的,可是你要确保finally的语句可以执行。而2-6恰巧是try语句块的内容。23这个索引恰巧是finally语句的一份复制。
END
我的公众号:石杉的架构笔记(ID:shishan100)
欢迎长按下图关注公众号:石杉的架构笔记!
公众号后台回复资料,获取做者独家秘制学习资料
石杉的架构笔记,BAT架构经验倾囊相授