Java异常处理中try,catch,finally代码块与return语句

先从一道面试题开始:

如果catch里面有return语句,请问finally的代码还会执行吗?
如果会,请问是在return前还是return后?
例如这段代码,最后主函数打印出的值是多少?是20还是30?

public static void main(String[] args) {
        System.out.println(testFinally());
    }
    public static int testFinally(){
        int i=0;
        {
            try {
                System.out.println(10/i);
                i=10;
                return i;
            } catch (Exception e) {
                i=20;
                return i;
            }
            finally {
                i=30;
                System.out.println("finally代码块执行了");
                return i;
            }
        }

答案揭晓:finally语句会被执行,执行时间既不在return前,也不在return后,而是让return先执行一半,最后finally执行完后再执行完return,主函数打印出的值为30。

这个回答可能让人疑惑,什么叫执行一半?catch中不是已经return了i值20吗?为什么会打印出30?

要解释清楚,必须首先知道,在Java运行时jvm(java虚拟机)会给每个调用的方法在内存的栈中产生栈帧,而如果方法会return一个值,那么这个方法所在的栈帧中会单独划分一片区域,用于存储return所要返回的值,例如下图:
图中代码不一样但意思相同
代码运行,出现异常,转入catch代码块,i被赋值为20,然后jvm执行return语句,将i的值20存入栈帧上负责存储return值的那块区域
注意,我们知道,finally代码块中的内容一定会被执行,所以jvm将i=20存入return区域后并未返回,而是先去执行finally代码块中的内容,jvm将执行i=30,然后又遇见了return语句,于是再次把新的i值存入return区域,这时不会再有代码打断这条return语句了,于是返回30;

假如finally代码块中没有return语句只有赋值语句呢?例如这样,输出的是20还是30?

    public static void main(String[] args) {
        System.out.println(testFinally());
    }
    public static int testFinally(){
        int i=0;
        {
            try {
                System.out.println(10/i);
                i=10;
            } catch (Exception e) {
                i=20;
                return i;
            }
            finally {
                i=30;
                System.out.println("finally");
            }
            System.out.println("我执行了");
            return i;
        }
    }

运行结果:

finally
20

答案是20,因为finally代码块中没有return也就不会去修改return区域中存储的值,finally代码块执行完毕后直接执行catch中的return,同时结束整个方法的调用,所以后面System.out.println(“我执行了”);这些代码也不会执行

### Javatry-catch-finally的执行顺序异常处理机制 在Java中,`try-catch-finally` 是一种用于捕获和处理程序运行时异常的结构。其执行顺序和异常处理机制如下: #### 1. `try` 块 `try` 块包含可能抛出异常的代码。如果 `try` 块中的代码没有抛出异常,则会正常执行完该块内的所有语句[^1]。 #### 2. 异常抛出 `catch` 块 如果 `try` 块中的代码抛出了异常,程序会立即停止执行 `try` 块剩余的部分,并跳转到异常类型匹配的第一个 `catch` 块。如果没有匹配的 `catch` 块,则异常会被传递给调用栈中的上一层方法处理[^2]。 #### 3. `finally` 块 无论是否发生异常,`finally` 块中的代码都会被执行。即使在 `try` 或 `catch` 块中有 `return` 语句,`finally` 块仍然会在方法返回之前执行[^3]。 #### 执行顺序示例 以下代码展示了 `try-catch-finally` 的执行顺序: ```java public class TestTryCatchFinally { public static void main(String[] args) { System.out.println(test("12")); } public static int test(String str) { try { Integer.parseInt(str); // 可能抛出 NumberFormatException return 1; // 如果没有异常,返回1 } catch (NumberFormatException e) { return -1; // 捕获异常并返回-1 } finally { System.out.println("test结束"); // 无论是否有异常,都会执行 } } } ``` 在上述代码中,`finally` 块中的语句总是在 `try` 或 `catch` 块之后执行,即使 `try` 或 `catch` 块中有 `return` 语句[^3]。 #### 异常处理机制 Java中的异常处理基于“抓抛模型”。当程序运行过程中遇到异常时,会生成一个异常对象并将其提交给Java运行时系统。如果当前方法无法处理该异常,则会将异常传递给调用者方法,这一过程称为“抛出”异常。调用者方法可以选择捕获并处理异常,或者继续将异常向上层方法传递,直到异常被处理或导致程序终止。 #### 多重 `catch` 块 可以为同一种类型的异常提供多个 `catch` 块以实现不同的异常分类处理。例如: ```java public class MultiCatchExample { public static void main(String[] args) { try { int[] arr = {1, 2, 3}; System.out.println(arr[10]); // ArrayIndexOutOfBoundsException } catch (ArrayIndexOutOfBoundsException e) { System.out.println("数组越界异常:" + e.getMessage()); } catch (Exception e) { System.out.println("其他异常:" + e.getMessage()); } finally { System.out.println("finally块执行"); } } } ``` 在此示例中,程序首先尝试访问数组的第11个元素(索引为10),这将抛出 `ArrayIndexOutOfBoundsException` 异常。由于第一个 `catch` 块能够处理该异常,因此不会进入第二个 `catch` 块[^4]。 ### 注意事项 - 如果 `try` 块中有 `return` 语句,`finally` 块仍会在方法返回之前执行。 - 如果 `try` 和 `catch` 块中都未处理某些异常,则这些异常会传播到调用栈的上层方法。 - `finally` 块通常用于释放资源(如关闭文件、数据库连接等)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值