如果大家对与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,很明显
- 0 - 11 行如果发生Class java/lang/ArithmeticException则跳转到21行开始执行。
- 0 - 11行没有发生异常,则跳转到35行开始执行,实际上你仔细看的话,会发现,35行之后是finally的那部分。
- 21 - 25行执行的是catch块里面的语句,执行完之后也会自动跳转到35行执行
- 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的内容,编译器帮我们添加进去了。编译器自动关闭资源的同时,也帮助我们把异常处理加了进去。如果有疑问的,欢迎评论,私信我。我有时间都会给大家回复解答的。