Java中finally使用注意事项

187 阅读3分钟

Java中finally使用注意事项

  在Java中try-catch-finally是用来做异常处理的,用法比较简单,但有些细节需要注意:

1. 在finally中使用return

如果在finally语句块中使用return语句,那么即使try-catch语句块中有return语句操作,也不会立马返回结果,而是在执行完finally语句块中的语句再返回。此时问题就产生了:如果finally语句块中存在return语句,则会直接返回finally语句块中的结果,从而无情的丢弃了try语句块中的返回值。

示例代码:

public static void main(String[] args) {
    System.out.println("执行结果: " + test1()); //错误示例 2
    System.out.println("执行结果: " + test2()); //正确示例 1
}

/**
 * 错误示例:
 * 如果在finally中存在return语句,那么try-catch中的return值都会被覆盖。
 * 所以在try-catch-finally中存在 return返回值的情况,一定要确保return语句只在方法的尾部出现一次。
 * @return 2
 */
private static int test1(){
    int r = 0;
    try{
        r = r + 1;
        return r; // 此处不返回值
    }catch (Exception e){
    }finally {
        r = 2;
        return  r; // 此处返回2
    }
}

/**
 * 正确示例:
 * 确保return语句只在此处出现一次
 * @return 1
 */
private static int test2(){
    int r = 0;
    try{
        r = r + 1;
    }catch (Exception e){
    }finally {
    }
    return r; //确保return 语句只在此处出现一次
}

2. finally中的代码"未执行"

如果在finally语句块中有修改返回变量值的代码,但无return语句,则返回值为try或catch语句块中返回变量值,就好像finally语句块中代码未执行一样。 原因: Java虚拟机会把finally语句块作为”子程序(subroutine)“直接插入到try语句块或者catch语句块的控制转移语句之前。 但是,还有另外一个不可忽视的因素,那就是在执行”子程序(subroutine)“(也就是finally语句块)之前,try或者catch 语句块会保留其返回值到本地变量表(Local Variable Table)中,待"子程序(subroutine)"执行完毕之后,再恢复保留的返回值到操作数栈中,然后通过return或者throw语句将其返回给该方法的调用者(invoker)。 因此如果在try-catch-finally中如果有对返回值变量的操作,一定要确保return语句只在方法的尾部出现一次!这样就能保证try-catch-finally语句块中所有操作代码都会生效。

示例代码:

public static void main(String[] args) {
    System.out.println("执行结果: " + test3()); //错误示例 1
    System.out.println("执行结果: " + test4()); //正确示例 3
}

/**
 * finally代码块中的代码"未执行"
 * 错误示例
 * @return 1
 */
private static int test3(){
    int r = 0;
    try{
        r = r + 1;
        return r;
    }finally {
        r = r + 2;
    }
}
/**
 * finally代码块中的代码"未执行"
 * 正确示例
 * @return 3
 */
private static int test4(){
    int r = 0;
    try{
        r = r + 1;
    }finally {
        r = r + 2;
    }
    return r;
}

注:出现以下情况finally语句块中的代码也可能不执行,如下:

  • 在try-catch语句块中执行了 System.exit;
  • 在try-catch语句块中出现了死循环;
  • 在finally语句块执行之JVM或服务器挂了。