【Java从入门到放弃 之 从字节码的角度异常处理】

如果大家对与java的异常使用还有问题或者还不太了解,建议先看一下我之前写的Java异常了解一下基本 的异常处理知识,再看这篇文章。

生成字节码

public class Test27 {

    public String testTryCatch() {
        try {
            int a = 1;
            int b = 0;
            return String.valueOf(a / b);
        } catch (ArithmeticException e) {
            return "divide 0 ";
        }
    }

    public String testTryCatchFinally() {
        try {
            int a = 1;
            int b = 0;
            return String.valueOf(a / b);
        } catch (ArithmeticException e) {
            return "divide 0 ";
        }finally {
            System.out.println("finally");
        }
    }

    public String testTryWithResource() {
        try {
            int a = 1;
            int b = 0;
            return String.valueOf(a / b);
        } catch (ArithmeticException e) {
            return "divide 0 ";
        }finally {
            System.out.println("finally");
        }
    }


}

执行javac命令编译成字节码文件

D:\project\mydemo\src\main\java\com\example\mydemo\test>javac Test27.java

Javap 命令的使用

javap 是 Java 提供的反汇编工具,用于将 Java 字节码文件(.class 文件)反汇编成人类可读的 Java 汇编代码(或者说是 Java 字节码的指令)。这对于理解 Java 编译器生成的字节码、学习 JVM 的工作原理、调试和优化代码都非常有用。

基本语法

javap [options] <classes>
D:\project\mydemo\src\main\java\com\example\mydemo\test>javap -c Test27.class

常用选项

  • -c:显示字节码指令(反汇编)。
  • -verbose:显示详细信息,包括类、字段、方法的签名和属性。
  • -l:显示行号和本地变量表信息。
  • -p:显示所有私有成员、受保护成员和默认(包)访问级别的成员。
  • -constants:显示静态常量池。
  • -classpath 或 -cp :指定类路径。
  • -s:显示内部类型签名。
  • -public:仅显示公共成员和类。
  • -protected:显示公共和受保护成员和类(默认行为)。
  • -package:显示公共和包访问级别的成员和类(不加 -p 时默认行为)。
  • -private:显示所有成员和类(包括私有成员)。

字节码文件

生成的完整的字节码文件我传上来了,有需要的可以下载,这里我们逐个分析每个方法的字节码。

testTryCatch

  public java.lang.String testTryCatch();
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_0
       3: istore_2
       4: iload_1
       5: iload_2
       6: idiv
       7: invokestatic  #7                  // Method java/lang/String.valueOf:(I)Ljava/lang/String;
      10: areturn
      11: astore_1
      12: ldc           #15                 // String divide 0
      14: areturn
    Exception table:
       from    to  target type
           0    10    11   Class java/lang/ArithmeticException

0到3行,是把1跟0这两个常量存到slot里面;4到6是把两个操作数入栈,然后做除法。然后下面是异常表,如果from0 to 10 发生异常,跳转到target11行处理。

testTryCatchFinally

  public java.lang.String testTryCatchFinally();
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_0
       3: istore_2
       4: iload_1
       5: iload_2
       6: idiv
       7: invokestatic  #7                  // Method java/lang/String.valueOf:(I)Ljava/lang/String;
      10: astore_3
      11: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
      14: ldc           #23                 // String finally
      16: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      19: aload_3
      20: areturn
      21: astore_1
      22: ldc           #15                 // String divide 0
      24: astore_2
      25: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
      28: ldc           #23                 // String finally
      30: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      33: aload_2
      34: areturn
      35: astore        4
      37: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
      40: ldc           #23                 // String finally
      42: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      45: aload         4
      47: athrow
    Exception table:
       from    to  target type
           0    11    21   Class java/lang/ArithmeticException
           0    11    35   any
          21    25    35   any
          35    37    35   any

这段字节码,我们主要观察Exception table,很明显

  1. 0 - 11 行如果发生Class java/lang/ArithmeticException则跳转到21行开始执行。
  2. 0 - 11行没有发生异常,则跳转到35行开始执行,实际上你仔细看的话,会发现,35行之后是finally的那部分。
  3. 21 - 25行执行的是catch块里面的语句,执行完之后也会自动跳转到35行执行
  4. 35 - 37行执行的是把异常class保存起来,以便执行throw的时候能正常抛出去。

testTryWithResource

  public java.lang.String testTryWithResource();
    Code:
       0: new           #31                 // class java/io/FileInputStream
       3: dup
       4: ldc           #33                 // String teset
       6: invokespecial #35                 // Method java/io/FileInputStream."<init>":(Ljava/lang/String;)V
       9: astore_1
      10: ldc           #37                 // String ok
      12: astore_2
      13: aload_1
      14: invokevirtual #39                 // Method java/io/FileInputStream.close:()V
      17: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
      20: ldc           #23                 // String finally
      22: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      25: aload_2
      26: areturn
      27: astore_2
      28: aload_1
      29: invokevirtual #39                 // Method java/io/FileInputStream.close:()V
      32: goto          41
      35: astore_3
      36: aload_2
      37: aload_3
      38: invokevirtual #44                 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
      41: aload_2
      42: athrow
      43: astore_1
      44: aload_1
      45: invokevirtual #50                 // Method java/io/IOException.printStackTrace:()V
      48: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
      51: ldc           #23                 // String finally
      53: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      56: goto          72
      59: astore        4
      61: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
      64: ldc           #23                 // String finally
      66: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      69: aload         4
      71: athrow
      72: ldc           #37                 // String ok
      74: areturn
    Exception table:
       from    to  target type
          10    13    27   Class java/lang/Throwable
          28    32    35   Class java/lang/Throwable
           0    17    43   Class java/io/IOException
          27    43    43   Class java/io/IOException
           0    17    59   any
          27    48    59   any
          59    61    59   any

最后这段字节码我就不带大家一起读了,实际上你自己看就会发现,实际上TryWithResource是语法糖,把之前我们写的一些cath的内容,编译器帮我们添加进去了。编译器自动关闭资源的同时,也帮助我们把异常处理加了进去。如果有疑问的,欢迎评论,私信我。我有时间都会给大家回复解答的。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ThetaarSofVenice

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值