Java中的try catch finally

来源:互联网 发布:网络保本理财产品排行 编辑:程序博客网 时间:2024/05/16 16:15

一直以为自己对try catch足够了解了,但是在看到这篇博客后才意识到自己了解的仅仅是皮毛。
首先要知道f inally不是一定会执行的.下面的情况下finally就肯定不会执行的。
(1)try语句没有被执行到,如在try语句之前就返回了,这样finally语句就不会执行, 这也说明了finally语句被执行的必要而非充分条件是:相应的try语句一定被执行到。
(2)在try块中有System.exit(0);这样的语句,System.exit(0);是终止Java虚拟机JVM的,连JVM都停止了,所有都结束了,当然finally语句也不会被执行到。

其次是finally究竟是什么时候执行
finally语句是在try的return语句执行之后,return返回之前执行。这句话理解起来很费劲,我们下面用debug的截图解释。
在执行finally代码时,如果finally代码本身没有退出的语句(return或抛出异常),finally执行完毕后还会返回try或catch,由try或catch执行退出指令。
try一定要配合catch或者finally一起使用
当finally中包含return时,就不能在try和finally之后写return了,只能在catch中写return了,否则会编译通不过。
我们先看看下面的代码:

package com.xfl.exception;/** * Created by XFL. * time on 2016/12/3 15:14 * description:异常捕获测试 * 在执行finally代码时,如果finally代码本身没有退出的语句(return或抛出异常), * finally执行完毕后还会返回try或catch,由try或catch执行退出指令 */public class TestException {    public static void main(String[] args) {        int result1 = test1();        int result2 = test2();        System.out.println("最终的结果是: " + result1);        System.out.println("最终的结果是: " + result2);    }    /**     * 出异常返回3,不出异常返回4.finally是在return之前执行的     *     * @return     */    private static int test1() {        int temp = 1;        try {            temp += 1;            int a = 1;            int b = (Math.random() * 10) % 3 > 1 ? 1 : 0;            int c = a / b;        } catch (Exception e) {            temp += 1;            System.out.println(temp);            /**             * Return并不是让函数马上返回,而是return语句执行后,将把返回结果放置进函数栈中,             * 此时函数并不是马上返回,它要执行finally语句后才真正开始返回。             * finally语句是在try的return语句执行之后,return返回之前执行             */            return temp;        } finally {            /**             * finally不是一定会执行的.             * (1)try语句没有被执行到,如在try语句之前就返回了,这样finally语句就不会执行,             * 这也说明了finally语句被执行的必要而非充分条件是:相应的try语句一定被执行到。             *(2)在try块中有System.exit(0);这样的语句,System.exit(0);是终止Java虚拟机JVM的,             * 连JVM都停止了,所有都结束了,当然finally语句也不会被执行到。             */            temp += 1;            System.out.println(temp);        }        temp += 1;        System.out.println(temp);        return temp;    }    /**     * 出异常返回4,不出异常返回3.finally是在return之前执行的     *     * @return     */    private static int test2() {        int temp = 1;        try {            temp += 1;            int a = 1;            int b = (Math.random() * 10) % 3 > 1 ? 1 : 0;            int c = a / b;        } catch (Exception e) {            temp += 1;            //执行return之前会先执行finally            System.out.println(temp);            return temp;        } finally {            temp += 1;            //finally中包含return时catch中的return不起作用了            System.out.println(temp);            return temp;        }    }}

我们分析test1方法出异常时的执行情况,出错时执行catch
这里写图片描述
此时catch中包含return语句,return并不是让函数马上返回,而是return语句执行后,将把返回结果放置进函数栈中,然后再执行finally部分
这里写图片描述
这里temp的值已经变成4了,执行完finally部分后,因为finally没有退出程序的语句,所以会返回到catch中。
这里写图片描述
虽然temp已经变成了4,但是真正返回的是3,因为这个return已经执行过了,前面已经将返回结果放到栈中了,这个时候执行return只是把栈中的值返回。(注意这里需要根据返回类型区分,如果是引用类型则在finally中对返回数据的修改是启作用的,如果是基本数据类型就不启作用了,猜测原因应该是Java的值传递,当是引用类型的时候,返回的并不是对象的内容,而是对象的引用)

现在来分析test2方法,此方法finally中包含了return语句
这里写图片描述
执行到catch中的return语句时先把返回值放入到栈中,再执行finally语句
这里写图片描述
执行到finally的return语句时,也会把返回值放入到栈中,这样前面的就不起作用了,因为finally包含程序退出语句,所以就不会再像test1方法中那样再次执行catch中的return了。这里真正返回的是4,而不是3.
这里写图片描述
上图是两个方法程序运行的结果。

现在我们来了解下Java Stacks。
所谓Java栈,描述的是一种Java中方法执行的内存模型,Java栈为线程私有,线程中每一次的方法调用(或执行),JVM都会为该方法分配栈内存,即:栈帧(Stack Frame),分配的栈帧用于存放该方法的局部变量表、操作栈(JVM执行的所有指令都是围绕它来完成的)、方法编译后的字节码指令信息和异常处理信息等,JVM指定了一个线程可以请求的栈深度的最大值,如果线程请求的栈深度超过这个最大值,JVM将会抛出StackOverflowError,注意,此处抛出的时Error而不是Exception。

1 0