卷向字节码-Java异常到底是怎么被处理的?(中)

简介: 卷向字节码-Java异常到底是怎么被处理的?(中)

所以,上面的消息汇总一下:

  • from:可能发生异常的起始点指令索引下标(包含)
  • to:可能发生异常的结束点指令索引下标(不包含)
  • target:在from和to的范围内,发生异常后,开始处理异常的指令索引下标
  • type:当前范围可以处理的异常类信息

知道了异常表之后,可以回答这个问题了:异常怎么被抛出的?

JVM 通过异常表,帮我们抛出来的。

异常表里面有啥?

前面我说了,不再赘述。

异常表怎么用呢?

简单描述一下:

1.如果出现异常了,JVM 会在当前的方法中去寻找异常表,查看是否该异常被捕获了。

2.如果在异常表里面匹配到了异常,则调用 target 对应的索引下标的指令,继续执行。

好,那么问题又来了。如果匹配不到异常怎么办呢?

我在官网文档的这里找到了答案:

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-3.html#jvms-3.12

它的示例代码是这样的:


image.png

意思就是如果抛出的值与 catchTwo 的任何一个 catch 子句的参数不匹配,Java虚拟机就会重新抛出该值,而不调用 catchTwo 的任何一个 catch 子句中的代码。

什么意思?

说白了就是反正我处理不了,我会把异常扔给调用方。

这是编程常识,大家当然都知道。

但是当常识性的东西,以这样的规范的描述展示在你面前的时候,感觉还是挺奇妙的。

当别人问你,为什么是这样的调用流程的时候,你说这是规定。

当别人问你,规定在哪的时候,你能把官网文档拿出来扔他脸上,指着说:就是这里。

虽然,好像没啥卵用。


稍微特殊的情况


这一趴再简单的介绍一下有 finally 的情况:

public class MainTest {
   public static void main(String[] args) {
       try {
           int a = 1 / 0;
       } catch (Exception e) {
           e.printStackTrace();
       } finally {
           System.out.println("final");
       }
   }
}

经过 javap 编译后,异常表部分出现了三条记录:

image.png


第一条认识,是我们主动捕获的异常。

第二三条都是 any,这是啥玩意?

答案在这:

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-3.html#jvms-3.13

image.png


主要看我画线的地方:

一个带有 finally 子句的 try 语句被编译为有一个特殊的异常处理程序,这个异常处理程序可以处理在 try 语句中抛出的(any)任何异常。

所有,翻译一下上面的异常表就是:

  • 如果 0 到 4 的指令之间发生了 Exception 类型的异常,调用索引为 15 的指令,开始处理异常。
  • 如果 0 到 4 的指令之间,不论发生了什么异常,都调用索引为 31 的指令(finally 代码块开始的地方)
  • 如果 15 到 20 的指令之间(也就是 catch 的部分),不论发生了什么异常,都调用索引为 31 的指令。

接着,我们把目光放到这一部分:



image.png


怎么样,发现了没?就问你神不神奇?

在源码中,只在 finally 代码块出现过一次的输出语句,在字节码中出现了三次。

finally 代码块中的代码被复制了两份,分别放到了 try 和 catch 语句的后面。再配合异常表使用,就能达到 finally 语句一定会被执行的效果。

以后再也不怕面试官问你为什么 finally 一定会执行了。

虽然应该也没有面试官会问这样无聊的问题。

问起来了,就从字节码的角度给他分析一波。

当然了,如果你非要给我抬个杠,聊聊 System.exit 的情况,就没多大意义了。

最后,关于 finally,再讨论一下这个场景:

public class MainTest {
    public static void main(String[] args) {
        try {
            int a = 1 / 0;
        } finally {
            System.out.println("final");
        }
    }
}

这个场景下,没啥说的, try 里面抛出异常,触发 finally 的输出语句,然后接着被抛出去,打印在控制台:

image.png

如果我在 finally 里面加一个 return 呢?

可以看到,运行结果里面异常都没有被抛出来:


image.png


为什么呢?

答案就藏在字节码里面:


image.png


其实已经一目了然了。

右边的 finally 里面有 return,并没有 athrow 指令,所以异常根本就没有抛出去。

这也是为什么建议大家不要在 finally 语句里面写 return 的原因之一。

目录
相关文章
|
10月前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
291 1
|
17天前
|
自然语言处理 前端开发 算法
Java编译器优化秘籍:字节码背后的IR魔法与常见技巧
编译器将源代码转换为机器码的过程中,会经历多个中间表达形式(IR)的转换与优化。前端生成高级IR(HIR),后端将其转为低级IR(LIR)并进行机器相关优化。Java编译流程包括源码到字节码、再由即时编译器转换为内部HIR(如SSA图)、优化后生成LIR,最终编译为机器码。常见优化技术包括常量折叠、值编号、死代码消除、公共子表达式消除等,旨在提升程序性能与执行效率。
58 0
|
3月前
|
Java 程序员 数据库连接
我们详细地讲解一下 Java 异常及要如何处理
我是小假 期待与你的下一次相遇 ~
|
10月前
|
Java API 调度
如何避免 Java 中的 TimeoutException 异常
在Java中,`TimeoutException`通常发生在执行操作超过预设时间时。要避免此异常,可以优化代码逻辑,减少不必要的等待;合理设置超时时间,确保其足够完成正常操作;使用异步处理或线程池管理任务,提高程序响应性。
474 13
|
10月前
|
Java
轻松上手Java字节码编辑:IDEA插件VisualClassBytes全方位解析
本插件VisualClassBytes可修改class字节码,包括class信息、字段信息、内部类,常量池和方法等。
486 6
|
10月前
|
Java
在 Java 中,如何自定义`NumberFormatException`异常
在Java中,自定义`NumberFormatException`异常可以通过继承`IllegalArgumentException`类并重写其构造方法来实现。自定义异常类可以添加额外的错误信息或行为,以便更精确地处理特定的数字格式转换错误。
162 1
|
6月前
|
SQL Java 中间件
【YashanDB知识库】yasdb jdbc驱动集成BeetISQL中间件,业务(java)报autoAssignKey failure异常
在BeetISQL 2.13.8版本中,客户使用batch insert向yashandb表插入数据并尝试获取自动生成的sequence id时,出现类型转换异常。原因是beetlsql在prepareStatement时未指定返回列,导致yashan JDBC驱动返回rowid(字符串),与Java Bean中的数字类型tid不匹配。此问题影响业务流程,使无法正确获取sequence id。解决方法包括:1) 在batchInsert时不返回自动生成的sequence id;2) 升级至BeetISQL 3,其已修正该问题。
【YashanDB知识库】yasdb jdbc驱动集成BeetISQL中间件,业务(java)报autoAssignKey failure异常
|
6月前
|
SQL druid Oracle
【YashanDB知识库】yasdb jdbc驱动集成druid连接池,业务(java)日志中有token IDENTIFIER start异常
客户Java日志中出现异常,影响Druid的merge SQL功能(将SQL字面量替换为绑定变量以统计性能),但不影响正常业务流程。原因是Druid在merge SQL时传入null作为dbType,导致无法解析递归查询中的`start`关键字。
|
7月前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
416 14
|
7月前
|
缓存 Java 应用服务中间件
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
1191 5

热门文章

最新文章