Java中try catch finally语句中含return语句的执行情况总结-编程陷阱

原创 2015年12月08日 16:11:34

前言:有java编程基础的人对java的异常处理机制都会有一定了解,而且可能感觉使用起来也比较简单,但如果在try catch finally语句块中遇到return语句,开发者可能就会遇到一些逻辑问题,甚至步入编程的陷阱。不信,我们先看看一段小程序,读者可以分析其逻辑然后猜测其输出结果:

public class Test {
    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.Test1());
    }

    public boolean Test1() {
        boolean b = true;
        try {
            int i = 10 / 0; 
            System.out.println("i = " + i);
            return true; 
        } catch (Exception e) {
            System.out.println(" -- catch --");
            System.out.println("b:" + b);
            return b = false; 
        } finally {
            System.out.println(" -- finally --");
            System.out.println("b:" + b);
        }
    }
}

请先停止继续阅读,试着说出其运行结果。
如果你不能很自信地正确说出这段程序的执行逻辑和结果,那本文就值得你一读,如果你可以,请忽略本文。
执行结果是:
– catch –
b:true
– finally –
b:false
false
你说对了吗?

正文
首先我们了解java的异常处理机制中try、catch、finally的基本执行逻辑。

  • try:包裹可能引发异常的代码
  • catch:可以有多个catch块,一个代码块对应一种异常类型,表明该catch块用于处理此类型的异常。
  • finally:主要用于回收在try块里使用的物理资源(比如数据库连接、网络连接和磁盘文件等),这些物理资源必须显示回收,因为java的垃圾回收机制不会回收任何的物理资源,垃圾回收机制只回收堆内存中对象所占用的内存。异常机制保证finally块内的代码总是被执行,除非在try块或者catch块中调用了退出虚拟机的方法(即System.exit(1);),此时程序直接退出,不再执行finally块。

首先明确其语法结构:
1. try块必存在, catch块和finally块都是可选的,但两者需至少出现其中之一,也可以同时出现;
2. 可以有多个catch块,捕获父类异常的catch块必须位于捕获子类异常的后面,即设计多个catch块捕获异常时要先捕获小的异常,再捕获大的异常。一般,try块后只有一个catch块会被执行,绝不可能有多个catch块被执行,除非使用continue开始下次循环时,再次执行到这个try、catch块,而捕获处理其他catch的异常;
3. 多个catch块必须位于try块之后,finally块必须位于所有catch块之后。

下面我们分情况讨论try、catch、finally中含有return的情况。
示例一(try、catch、finally中都有return):

public class Test {
    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.Test1());
    }

    public boolean Test1() {
        try {
            int i = 10 / 0; // 抛出 Exception,try中其他代码不执行,进入catch
            System.out.println("i = " + i);
            return true; 
        } catch (Exception e) {
            System.out.println(" -- catch --");
            return false;
        } finally {
            System.out.println(" -- finally --");
            return true;
        }
    }
}

Eclipse中,这段代码会出警告:finally block does not complete normally。译为:finally块不能正常完成。Java不建议在finally块中使用renturn或throw等导致方法终止的语句,否则将会导致try块、catch块中的return、throw语句失效。但是仍然可以执行,结果为:
– catch –
– finally –
true
这里最后打印的true即时finally中返回的true。至于为什么会覆盖,这个涉及到JVM底层字节码的具体实现和一些指令操作,具体可以参考这里:JVM中finally子句介绍 如果没有JVM和计算机组成原理以及操作系统的相关基础知识是较难以理解的,有余力的开发者可以深入研究。

实例二(try、catch中有return,finally中无):

public class Test {
    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.Test1());
    }

    public boolean Test1() {
        try {
            int i = 10 / 0; // 抛出 Exception,try中其他代码不执行,进入catch
            System.out.println("i = " + i);
            return true; // 不会执行
        } catch (Exception e) {
            System.out.println(" -- catch --");
            return false; // Exception 抛出,获得了返回false的机会
        } finally {
            System.out.println(" -- finally --");
        }
    }
}

执行结果:
– catch –
– finally –
false

断点调试可发现其逻辑:在finally执行后,又回到catch语句里面的return上,然后返回这句中的false。然后,很多人就会认为,甚至很多技术博客都写到:只有finally块执行完成之后,才会回来执行try或者catch块中的return语句。 但是!!真的是这样吗?也许是说这话的人知道意思但表达不够清楚,以至于让笔者觉得是误人子弟,try、catch中的rerun语句的逻辑是否执行?执行完finally块后一定会返回去执行try、catch吗?我们回过头来看开篇的那段代码:

public class Test {
    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.Test1());
    }
    public boolean Test1() {
        boolean b = true;
        try {
            int i = 10 / 0; 
            System.out.println("i = " + i);
            return true; 
        } catch (Exception e) {
            System.out.println(" -- catch --");
            System.out.println("b:" + b);
            return b = false; 
        } finally {
            System.out.println(" -- finally --");
            System.out.println("b:" + b);
        }
    }
}

代码中我们将catch中的return语句加上了一个赋值操作,断点调试,可以发现,程序执行到int i = 10 / 0; 语句后跳出catch块,并完整执行到return b = false; 然后进入finally块,执行两条输出语句,第二条System.out.println(“b:” + b);这里的b变成了false!,说明之前return中的赋值语句有执行,执行完finally后,程序再次进入catch中的return,返回给调用者。所以事实是,当Java程序执行try块、catch块遇到return语句时,当系统执行完return语句之后,并不会立即结束该方法,而是去寻找该异常处理流程中是否包含finally块,如果没有finally块,方法终止,返回相应的返回值。如果有finally块,系统立即开始执行finally块——只有当finally块执行完成后,系统才会再次跳回来根据return语句结束方法。如果finally块里使用了return语句来导致方法结束,则finally块已经结束了方法,系统不会跳回去执行try、catch块里的任何代码。

依照此标准,下列程序应该输出什么?

public class Test {
    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.test());
    }

    public static int test() {
        int count = 5;
        try {
            return ++count;
        } catch (Exception e) {
            // TODO: handle exception
        } finally {
            System.out.println("finally()执行");
            return count++;
        }
    }
}

答案是:
finally()执行
6

下面还有一个较难的判断程序:

public class Test {
    public static void main(String[] args) {
        int a  = test();
        System.out.println(a);
    }

    public static int test() {
        int count = 5;
        try {
            throw new RuntimeException("测试异常");
        } catch (Exception e) {
            // TODO: handle exception
        } finally {
            System.out.println("finally()执行");
            return count;
        }
    }
}

运行结果:
finally()执行
5

一般读者可能以为上面程序会抛出异常,test()方法非正常终止,test()方法应该没有返回值。但事实上,test()方法完全可以正常结束,而test()方法返回了5,看起来throw语句完全失去了作用。
不过,依然按照标准分析,系统执行throw语句时并不会立即抛出异常,而是去寻找该异常处理流中是否包含finally块。如果没有finally块,程序立即抛出异常;如果有finally块,系统立即开始执行finally块——只有当finally块执行完成后,系统才会再次跳回来抛出异常。如果finally块里使用return语句来结束方法,系统将不会跳回去执行try块、catch块去抛出异常。

实践是检验真理的唯一标准。学会用质疑的眼光求真,用踏实的态度去实践,是每一个成熟的技术人员所必须的。

请尊重原创,转载请注明出处:
http://blog.csdn.net/daijin888888/article/details/48369809

版权声明:本文为博主原创文章,未经博主允许不得转载。博主地址:http://blog.csdn.net/daijin888888

java面试题20--如果catch里面有return语句,finally里面的代码还会执行吗?

会 return 后代码示例: /* * java面试题20--如果catch里面有return语句,finally里面的代码还会执行吗? */ public class FinallyDemo...
  • u014726937
  • u014726937
  • 2016年12月28日 15:51
  • 2331

catch中有return

1、如果catch里面有return语句,请问finally里面的代码还会执行吗?如果会,请问是在return前面,还是在return后面?(答案:会,前) 解释说明: public class ...
  • u011182412
  • u011182412
  • 2016年11月14日 17:05
  • 244

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

结论: 1、不管有木有出现异常,finally块中代码都会执行; 2、当try和catch中有return时,finally仍然会执行; 3、finally是在return后面的表达式运算后执行...
  • kavensu
  • kavensu
  • 2012年10月13日 17:25
  • 173731

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

有return的情况下try catch finally的执行顺序
  • jsjdtb356
  • jsjdtb356
  • 2016年08月09日 11:08
  • 850

try catch finally,try里有return,finally还执行么?(最强总结)

try catch finally,try里有return,finally还执行么?(最强总结)
  • qq_23490875
  • qq_23490875
  • 2016年12月26日 15:25
  • 921

关于异常处理:在catch语句能return吗?

转自:http://www.disandu.com/archives/1181   今天工作时无意中写出了这样的代码      bool func()       {           ...
  • ThinkHY
  • ThinkHY
  • 2010年08月12日 22:30
  • 8775

java捕获到异常以后,后面的代码还会执行吗?

转自:http://zhidao.baidu.com/link?url=BgAg2K6tQumyPRJyjIWCGEQe-knlVG-N67MUp1QoZyvkzvb7qZ3QpLz101rtAOqk...
  • suyu_yuan
  • suyu_yuan
  • 2016年09月22日 10:15
  • 6808

java中的异常以及 try catch finally以及finally的执行顺序

java try、catch、finally及finally执行顺序详解 1.为什么要用finally 先看一个没有finally的异常处理try-catch语句: 假设count...
  • QH_JAVA
  • QH_JAVA
  • 2013年10月21日 21:43
  • 14301

Java语言中try-catch-finally的执行顺序

最近遇到一道Java编程题目,让根据以下程序写输出: public static int func (){ try{ return 1; }catch (Excepti...
  • MOLIILOM
  • MOLIILOM
  • 2016年03月17日 00:26
  • 1760

Java面试题—try语句中执行return语句

题目:try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?public class TryCatchDe...
  • hp910315
  • hp910315
  • 2015年12月15日 18:42
  • 1417
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java中try catch finally语句中含return语句的执行情况总结-编程陷阱
举报原因:
原因补充:

(最多只允许输入30个字)