关闭

finally中使用return会吃掉catch中抛出的异常

标签: 面向对象编程Java
6261人阅读 评论(2) 收藏 举报
分类:

今天学习大神的文章:深入理解java异常处理机制 学到一个有意思的知识点。如果在finally中使用return会吃掉catch中抛出的异常。

看例子:

[java] view plaincopy
  1. public class TestException {  
  2.     public TestException() {  
  3.     }  
  4.   
  5.     boolean testEx() throws Exception {  
  6.         boolean ret = true;  
  7.         try {  
  8.             ret = testEx1();  
  9.         } catch (Exception e) {  
  10.             System.out.println("testEx, catch exception");  
  11.             ret = false;  
  12.             throw e;  
  13.         } finally {  
  14.             System.out.println("testEx, finally; return value=" + ret);  
  15.             return ret;  
  16.         }  
  17.     }  
  18.   
  19.     boolean testEx1() throws Exception {  
  20.         boolean ret = true;  
  21.         try {  
  22.             ret = testEx2();  
  23.             if (!ret) {  
  24.                 return false;  
  25.             }  
  26.             System.out.println("testEx1, at the end of try");  
  27.             return ret;  
  28.         } catch (Exception e) {  
  29.             System.out.println("testEx1, catch exception");  
  30.             ret = false;  
  31.             throw e;  
  32.         } finally {  
  33.             System.out.println("testEx1, finally; return value=" + ret);  
  34.             return ret;  
  35.         }  
  36.     }  
  37.   
  38.     boolean testEx2() throws Exception {  
  39.         boolean ret = true;  
  40.         try {  
  41.             int b = 12;  
  42.             int c;  
  43.             for (int i = 2; i >= -2; i--) {  
  44.                 c = b / i;  
  45.                 System.out.println("i=" + i);  
  46.             }  
  47.             return true;  
  48.         } catch (Exception e) {  
  49.             System.out.println("testEx2, catch exception");  
  50.             ret = false;  
  51.             throw e;  
  52.         } finally {  
  53.             System.out.println("testEx2, finally; return value=" + ret);  
  54.             return ret;  
  55.         }  
  56.     }  
  57.   
  58.     public static void main(String[] args) {  
  59.         TestException testException1 = new TestException();  
  60.         try {  
  61.             testException1.testEx();  
  62.         } catch (Exception e) {  
  63.             e.printStackTrace();  
  64.         }  
  65.     }  
  66. }  

运行结果:

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

有点奇怪,下层方法抛出的异常竟然没有被捕获。

如果把return和throw放在一起,直接会提示错误。"Unreachable statement"(无法被执行).

然而finally却可以成功骗过编译器让两者并存(是不是可以算是编译器的一个小bug呢),结果是后执行的会覆盖前者。finally如果有return会覆盖catch里的throw,同样如果finally里有throw会覆盖catch里的return。

进而如果catch里和finally都有return finally中的return会覆盖catch中的。throw也是如此。

这样就好理解一些了,retrun和throw都是使程序跳出当前的方法,自然就是冲突的。如果非要跳出两次那么后者会覆盖前者。


在《java编程思想》中也有类似的例子,放在这里一起讨论。

“9.6.2 缺点:丢失的违例
一般情况下,Java的违例实施方案都显得十分出色。不幸的是,它依然存在一个缺点。尽管违例指出程序里存在一个危机,而且绝不应忽略,但一个违例仍有可能简单地“丢失”。在采用finally从句的一种特殊配置下,便有可能发生这种情况”

class VeryImportantException extends Exception{
    public String toString(){
        return "A very important exception";
    }
}

class HoHumException extends Exception{
    public String toString() {
        return "A trivial exception";
    }
}
public class LostMessage {
    void f() throws VeryImportantException{
        throw new VeryImportantException();
    }

    void dispose() throws HoHumException{
        throw new HoHumException();
    }

    public static void main(String[] args) throws Exception{
        LostMessage lm = new LostMessage();
        try{
            lm.f();
        }finally {
            lm.dispose();
        }
            
    }
}

输出:

Exception in thread "main" A trivial exception
at com.test.exception.LostMessage.dispose(LostMessage.java:24)
at com.test.exception.LostMessage.main(LostMessage.java:32)

“这是一项相当严重的缺陷,因为它意味着一个违例可能完全丢失。而且就象前例演示的那样,这种丢失显得非常“自然”,很难被人查出蛛丝马迹。而与此相反,C++里如果第二个违例在第一个违例得到控制前产生,就会被当作一个严重的编程错误处理。或许Java以后的版本会纠正这个问题(上述结果是用Java 1.1生成的)。”

书中的例子更加犀利,我们尽量避免这样的事情发生吧。

1
0
查看评论

有return的情况下try catch finally的执行顺序(最有说服力的总结)

结论: 1、不管有木有出现异常,finally块中代码都会执行; 2、当try和catch中有return时,finally仍然会执行; 3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都...
  • kavensu
  • kavensu
  • 2012-10-13 17:25
  • 173585

return与finally到底谁先执行?

关于return与finally的强弱关系的解释。其中返回值的一些注意事项
  • zoujian1993
  • zoujian1993
  • 2015-04-29 10:11
  • 1021

finally语句到底是在return之前还是之后执行?

参考:http://blog.csdn.net/kavensu/article/details/8067850代码示例:http://www.cnblogs.com/lanxuezaipiao/p/3440471.html结论:1、不管有木有出现异常,finally块中代码都会执行;2、当try和c...
  • xx326664162
  • xx326664162
  • 2015-12-11 18:37
  • 3708

C#:在catch中return,会执行finally吗?

请参考下面一段简单的语句块:1:  try2:  {3:      throw new Exception("new exception");4:  }5:  catch(Exception ex)6...
  • vipxiaotian
  • vipxiaotian
  • 2007-03-08 11:56
  • 7009

finally块中包含return语句对返回值的影响

要想弄清楚这个问题,最好是从字节码指令的层次进行分析,我们以如下代码段进行举例:public int test() { int i=0; try { i = 1; return i; } finally ...
  • jb_peng
  • jb_peng
  • 2016-08-19 19:42
  • 1426

以字节码角度解释return和finally的执行顺序?

前言(Preface): 关于return和finally的执行顺序,算是一个“老梗”了吧,大家众说纷纭,相信很多人已经看过很多版本的解释。但有些人可能只是通过简单的代码测试得出来的结论,没有从根本上解释这个问题。Java编译器把代码编译成字节码,我们通过反汇编字节码,查看字节码指令顺序,能根本地解...
  • u012557814
  • u012557814
  • 2016-03-01 13:44
  • 909

finally+return+异常

public class Test {public static void main(String[] args) { Test t=new Test(); System.out.println(t.test1()); System.out.println(t.test2()...
  • zhou920786312
  • zhou920786312
  • 2017-06-23 08:56
  • 160

finally语句到底是在return之前还是之后执行?

转自:http://www.cnblogs.com/lanxuezaipiao/p/3440471.html 网上有很多人探讨Java中异常捕获机制try...catch...finally块中的finally语句是不是一定会被执行?很多人都说不是,当然他们的回答是正确的,经过我试验,至少有两种...
  • superit401
  • superit401
  • 2016-08-12 21:51
  • 3590

java中finally与return的执行顺序详解

一些准备知识:     首先为了说明白java中finally与return的执行顺序是怎样的这个问题,我们需要做一点准备工作。     java方法是在栈幀中执行,栈幀是线程私有栈的单位,执行方法的线程会为每一个方法分配一小块栈空间来作为该方法执行时的内存空...
  • qj19842011
  • qj19842011
  • 2015-05-12 21:16
  • 6053

关于try,finally里面的return,到底谁先执行的问题

在JAVA语言的异常处理中,finally里面代码块是为了保证无论出现了什么样的情况,finally里的代码一定会被执行。但是return 的意思就是结束当前函数的调用并跳出这个函数,因此finally块里面的代码也是在return前执行,如果try finally里都有return,那么 ...
  • java19950529
  • java19950529
  • 2016-07-27 11:49
  • 2593
    个人资料
    • 访问:999870次
    • 积分:6279
    • 等级:
    • 排名:第4643名
    • 原创:75篇
    • 转载:63篇
    • 译文:0篇
    • 评论:130条
    文章分类
    最新评论