Java异常系列之finally的真正运行时机

1,964 阅读3分钟

异常是Java核心中非常重要的一个概念,但却很容易被大家忽略,这个系列我们会深入讲一下这个话题。学完这个系列,相信会让你对异常体系以及异常的各种使用场景,了如指掌,成为你职业进阶的必备技能。

名称 状态
finally 的真正运行时机 已完成
try-with-resources 语句 已完成
Java 异常体系 创作中...
catch 中的异常参数 创作中...
Java 异常链 创作中...
SpringMVC 中的异常处理 创作中...
自定义 SpringMVC 的异常处理链 创作中...

在之前的 Java语法糖 : 使用 try-with-resources 语句安全地释放资源 一文中,我们介绍了如何通过 try-with-resources 语句来代替丑陋的 finally 块。

但 try-with-resources 语句仅仅适用于自动关闭资源,有些场景下我们需要无论一段代码发生异常与否,都需要执行另外一段代码,这个时候就需要使用 finally 块了。

如果有人问你 发生异常以后 finally 块的内容什么时候会执行?你也许会毫不犹豫地回答:当然是执行完 catch 块的内容以后执行了。

但有时候你的回答也许没法这么干脆,比如下面这个例子。

当在 catch 块和 finally 块同时return的时候,到底会return什么呢?

public static int testFinally1() {
    try {
        Integer.parseInt("exception here");
    } catch (Exception e) {
        System.out.println("catch block 1");
        return 11;
    } finally {
        System.out.println("finally block 1");
        return 12;
    }
}

事实上,即使 catch 块有return语句, finally 块必然执行的逻辑还是成立的。上面的方法,return的是12。先输出catch block 1,然后输出finally block 1,最后返回12

不知道你发现规律没有,下面再举个例子你就更清晰了。

public static int testFinally3() {
    try {
        System.out.println("start");
        Integer.parseInt("testFinally3");
        System.out.println("never run");
    } catch (Exception e) {
        System.out.println("catch block 3");
        return iamReturn();
    } finally {
        System.out.println("finally block 3");
    }
    return 31;
}

public static int iamReturn() {
    System.out.println("return block");
    return 666;
}

思考一下执行这个方法会分别输出和返回什么?

先别着急看答案,根据我们之前发现的规律, finally 块必然执行,而 catch 块的非return部分需要在 finally 块之前执行。那么最终返回的应该是666

答案确实如此。下面是控制台输出的顺序:

start
catch block 3
return block
finally block 3

由此,我们可以总结 finally 块的真正运行时机了:

  1. finally 块必然执行,不论发生异常与否,也不论在 finally 之前是否有return
  2. 不管在 try 块中还是在 catch 块中包含 return,finally 块总是在 return 之前执行。
  3. 如果 finally 块中有return,那么 try 块和 catch 块中的 return 就没有执行机会了。

如果你真的理解了finally 块的真正运行时机,那么请思考一下,下面程序的返回值是21还是22,欢迎留言讨论。

 public static int testFinally2() {
    try {
        System.out.println("start");
        return 21;
    } catch (Exception e) {
        System.out.println("catch block 2");
    } finally {
        System.out.println("finally block 2");
    }
    return 22;
}

Wechat-westcall