Java异常丢失原因之猜想

先来看段代码:

public class ExceptionHandler {  
    public ExceptionHandler() {  
    }  
  
    boolean testEx() throws Exception {  
        boolean ret = true;  
        try {  
            ret = testEx1();  
        } catch (Exception e) {  
            System.out.println("testEx, catch exception");  
            ret = false;  
            throw e;  
        } finally {  
            System.out.println("testEx, finally; return value=" + ret);  
            return ret;  
        }  
    }  
  
    boolean testEx1() throws Exception {  
        boolean ret = true;  
        try {  
            ret = testEx2();  
            if (!ret) {  
                return false;  
            }  
            System.out.println("testEx1, at the end of try");  
            return ret;  
        } catch (Exception e) {  
            System.out.println("testEx1, catch exception");  
            ret = false;  
            throw e;  
        } finally {  
            System.out.println("testEx1, finally; return value=" + ret);  
            return ret;  
        }
    }  
  
    boolean testEx2() throws Exception {  
        boolean ret = true;  
        try {  
            int b = 12;  
            int c;  
            for (int i = 2; i >= -2; i--) {  
                c = b / i;  
                System.out.println("i=" + i);  
            }  
            return true;  
        } catch (Exception e) {  
            System.out.println("testEx2, catch exception");  
            ret = false;  
            throw e;  
        } finally {  
            System.out.println("testEx2, finally; return value=" + ret);
            return ret;
        }
        
    }  
    
public static void main(String[] args) {  
        ExceptionHandler testException1 = new ExceptionHandler();  
        try {  
            testException1.testEx();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}

结果如下:

i=2
i=1
testEx2, catch exception
testEx2, finally; return value=false
testEx1, finally; return value=false
testEx, finally; return value=false

我相信这个结果一定出乎很多人的意外,好像testEx2中最后抛出的异常丢失了,这就是我们通常说的异常丢失。那么,异常丢失是怎样造成的呢?我们还是祭出我们的手术刀javap来看看。

先看看testEx2函数的字节码

  boolean testEx2() throws java.lang.Exception;
    Code:
       0: iconst_1      
       1: istore_1      
       2: bipush        12
       4: istore_2      
       5: iconst_2      
       6: istore        4
       8: goto          42
      11: iload_2       
      12: iload         4
      14: idiv          
      15: istore_3      
      16: getstatic     #22                 // Field java/lang/System.out:Ljava/io/PrintStream;
      19: new           #36                 // class java/lang/StringBuilder
      22: dup           
      23: ldc           #66                 // String i=
      25: invokespecial #40                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      28: iload         4
      30: invokevirtual #68                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      33: invokevirtual #46                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      36: invokevirtual #30                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      39: iinc          4, -1
      42: iload         4
      44: bipush        -2
      46: if_icmpge     11
      49: goto          66
      52: astore_2      
      53: getstatic     #22                 // Field java/lang/System.out:Ljava/io/PrintStream;
      56: ldc           #71                 // String testEx2, catch exception
      58: invokevirtual #30                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      61: iconst_0      
      62: istore_1      
      63: aload_2       
      64: athrow        
      65: pop           
      66: getstatic     #22                 // Field java/lang/System.out:Ljava/io/PrintStream;
      69: new           #36                 // class java/lang/StringBuilder
      72: dup           
      73: ldc           #73                 // String testEx2, finally; return value=
      75: invokespecial #40                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      78: iload_1       
      79: invokevirtual #42                 // Method java/lang/StringBuilder.append:(Z)Ljava/lang/StringBuilder;
      82: invokevirtual #46                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      85: invokevirtual #30                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      88: iload_1       
      89: ireturn       
    Exception table:
       from    to  target type
           2    52    52   Class java/lang/Exception
           2    65    65   any

可以看到,finally语句块对应的字节码一开始就有pop操作,而catch语句开在结束的时候通过athrow指令将栈顶的异常抛出,这一对正反操作正好把栈上的异常对象的引用给丢掉了,从而造成了异常丢失现象。testEx1和testEx函数的字节码这里就不再赘述,大家自行观察。


注:由于目前还未找到观察操作数栈的工具,无法对上述内容进行验证,作者不对内容的正确性负责。另外,如果哪位朋友知道观察操作数栈的方法或工具,请不吝告知,谢谢!MAIL:zxh65 at sohu.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值