一、异常处理的抛出异常指令概述:
athrow指令
在ava程序中显示抛出异常的操作(throw语句)都是由athrow指令
来实现
除了使用throw语句显示抛出异常情况之外,JVN规范还规定了许多运行时异常会在其他Java虚拟机指令检测到异常状况时自动抛出。
例如在之前介绍的整数运算时,当除数为零时
虚拟机会在 idiv或ldiv指令中抛出ArithmeticException
异常
注意如下:
正常情况下,操作数栈的压入弹出都是一条条指令完成的。唯一的例外情况是在抛异常时,Java虚拟机会清除操作数栈上的所有内容,而后将异常实例压入调用者操作数栈上
。
简单介绍异常及异常处理过程
异常对象的生成过程:throw(手动 / 自动) 使用指令:athrow
异常的处理抓抛模型:try、catch、finally ,使用异常表
接下来我们使用示例代码来体会指令athrow的过程是怎么样的?
public class ExceptionTest{
public void throwzero(int i){
if(i == 0){
throw new RuntimeException(“参数值为0");
}
)
}
接下来我们编译代码使用插件查看具体的字节码是怎么样的?以及具体做了哪些事情?
接下来我们使用下一个示例代码来体会一下方法声明异常有何不同
public class ExceptionTest{
public void throwOne(int i)throw RuntimeException{
if(i == 1){
throw new RuntimeException(“参数值为1");
}
)
}
接下来我们看看编译字节码看看有显示抛出异常与无显示抛出异常有何区别?
二、异常处理的异常处理与异常表概述:
原异常处理:
在Java虚拟机中,处理异常(catch语句)不是由字节码指令来实现的(早期使用jsr、ret指令),而是采用异常表来完成的
异常表处理:
如果一个方法定义了一个try-catch或者try-finally的异常处理,就会创建一个异常表。
它包含了每个异常处理或者finally块的信息。异常表保存了每个异常处理信息。比如:
- 起始位置
- 结束位置
- 程序计数器记录的代码处理的偏移地址
- 被捕获的异常类在常量池中的索引
当一个异常被抛出时,JVW会在当前的方法里寻找一个匹配的处理,如果没有找到,这个方法会强制结束并弹出当前栈帧
,并且异常会重新抛给上层调用的方法(在调用方法栈帧)。
如果在所有栈帧弹出前仍然没有找到合适的异常处理,这个线程将终止
如果这个异常在最后一个非守护线程里抛出,将会导致JVM自己终止
,比如这个线程是个main线程
不管什么时候抛出异常,如果异维处理最终匹配了所有异常类型,代码就会继续执行
,在这种情况下如果方法结束后没有抛出异常,仍然执行finally块,在return前,它直接跳到finally块来完成目标
接下来我们使用示例代码来体会异常表的过程是怎么样的?
public class ExceptionTest{
public void tryCatch(){
try{
File file = new File("d://hello.text");
FileInputstream fis = new FileInputstream(file);
String info = "he1lo!";
}catch (FileNotFoundException e) {
e.printstackTrace( );
}catch( RuntimeException e){
e.printstackTrace();
}
}
}
接下来我们编译代码使用插件查看具体的字节码是怎么样的?
接下来我们分析一下字节码指令,看看具体做了哪些事情?
那么就会有小伙伴好奇,怎么指令22的位置后面还有其他指令呢?是怎么回事?我们看看该类的异常表结构
接下来我们再看一个示例代码,想想思考它的字节码会怎么做呢?
public class ExceptionTest{
//思考:如下方法返回结果为多少?
public static string func(){
string str = "helo";
try{
return str;
}
finally{
str = "atguigu";
}
}
public static void main( String[] args) {
system.out.println(func());
}
}
接下来我们编译代码使用插件查看具体的字节码是怎么样的?并做了哪些事情?