Java 异常的分类及处理

=======

当Java 运行时环境接收到异常对象时,如果为该对象寻找catch块呢?

当 Java运行时环境接收到异常对象后,会依次判断该异常对象是否是catch块后异常类或其子类的实例,如果是,Java运行环境将调用该catch块来处理该异常;否则再次拿该异常对象和下一个catch块里的异常类进行比较。Java 异常捕获如下图:

Java 异常的分类及处理

try 块后可以有多个catch块,这是为了针对不同的异常类提供不同的异常处理方式。当系统发生不同的意外情况时,系统会生成不同的异常对象,Java运行时就会根据该异常对象所属的异常类来决定使用哪个catch块来处理该异常。

try代码块

======

  • try : 监视代码执行过程,一旦发现异常则直接跳转 值catch,如果没有catch,则直接跳转至finally

  • catch : 可选执行的代码块 ,如果没有任何异常发生则不会执行;如果发现异常则进行处理或者向上抛出。这一切都在catch代码 快照红执行

  • finally: 必选执行的代码块,不管是否有异常产生,即使发生OutofMemoryError也会执行,通常用于善后清理工作。

如果finally代码块没有执行,有三种可能

1.没有进入try代码块

2.进入 try代码块,但是代码运行中出现了死循环或者死锁状态

3.进入try代码块,但是执行了Sytem.exit()操作

注意:finally 是在return 表达式运行后执行的,此时将要return的结果已经被暂存起来,待finally代码块执行结束后再将之前暂存的结果返回。示例代码如下:

public static int test(){

int temp = 10000;

try{

throw new Exception(“”);

}catch (Exception e){

return ++temp;

}finally {

temp = 9999;

}

}

我们从字节码操作来看返回的结果:

此方法的返回值是 10001而不是9999;

0 sipush 10000

3 istore_0 # 将栈顶int类型值保存到局部变量0中。 将 10000存在 slot_0上

4 new #5 <java/lang/Exception>

7 dup

8 ldc #6

10 invokespecial #7 <java/lang/Exception. : (Ljava/lang/String;)V>

13 athrow

14 astore_1 #将栈顶引用类型值保存到局部变量1中。

15 iinc 0 by 1 # 对变量temp 进行 + 1 操作

18 iload_0 # 从局部变量0中装载int类型值入栈。

19 istore_2 # 将栈顶int类型值保存到局部变量2中。

20 sipush 9999 # 将9999存储到slot_0上

23 istore_0

24 iload_2 #方法返回值的时候,直接提取的是 slot_2的值,即10001

25 ireturn

26 astore_3

27 sipush 9999

30 istore_0

31 aload_3

32 athrow

finally的职责:不是对变量进行赋值等操作,而是清理资源、释放连接、关闭管道流等操作。

finally 代码块中使用return语句,使返回值的判断更加复杂,所以避免返回值不可控,我们不要在finally代码块中使用 return 语句。

try代码块与锁的关系,lock方法可能会抛出unchecked异常,如果挡在try代码块中,必然触发finally 中的unlock 方法执行。对未加锁的对象解锁会抛出unchecked异常,如

IllegalMonitorStateExecption ,虽然是因为加锁失败而造成程序中断的,但是真正的加锁失败的原因可能会被后者覆盖。所以在try代码块之前调用lock()方法,避免由于加锁失败导致 finally 调用unlock() 抛出异常。代码如下

Lock lock = new xxxLock();

try{

// 无论加锁是否成功,unlock 都会执行

lock.lock();

doSomething();

}finally{

lock.unlock();

}

Lock、ThreadLocal、InputStream等这些需要进行强制释放和清除的对象都得在finally代码块中进行显示的清理,避免产生内存泄漏或者资源消耗

那么为什么finally代码块为什么一定会执行呢

我们看下面代码的字节码分析

public void foo() {

try {

tryItOut1();

} catch (MyException1 e) {

handleException(e);

} finally {

handleFinally();

}

}

对应的字节码如下:

Java 异常的分类及处理

可以看到,字节码中包含了三份 finally 语句块,都在程序正常 return 和异常 throw 之前。其中两处在 try 和 catch 调用 return 之前,一处是在异常 throw 之前。

Java 采用方式是复制 finally 代码块的内容,分别放在 try catch 代码块所有正常 return 和 异常 throw 之前。

相当于如下的代码:

public void foo() {

try {

tryItOut1();

handleFinally();

} catch (MyException1 e) {

handleException(e);

handleFinally();

} catch (Throwable e) {

handleFinally();

throw e;

}

}

异常的处理思路

=======

处理异常程序,需要解决一下三个问题:

(1) 哪里发生异常

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值