在Java(以及许多其他支持异常处理的编程语言)中,try-catch-finally 结构是一种强大的错误处理机制,它允许开发者在代码中优雅地处理可能出现的运行时错误。

然而,当try块中包含return语句时,finally块的执行顺序和时机可能会让初学者感到困惑。

基本概念

  • try 块:用于包裹可能抛出异常的代码。

  • catch 块(可选):用于捕获并处理try块中抛出的异常。可以有多个catch块来捕获不同类型的异常。

  • finally 块(可选):无论是否捕获到异常,finally块中的代码都会被执行。它主要用于执行必要的清理工作,如关闭文件、释放资源等。

try块中包含return语句时,执行流程会按照以下步骤进行:

  1. 执行try块中的代码:如果try块中的代码正常执行到return语句,则准备返回结果。
  2. 执行finally块:在返回结果之前,finally块中的代码会被执行。这意味着finally块中的代码会在return语句之后的返回值被实际返回给调用者之前执行。
  3. 返回结果:finally块执行完毕后,try块中的return语句的结果会被返回。

下面四类场景给大家演示下:

1. 若try{}中没有异常,则try{}中语句执行到return前一句,然后执行finally{}中的语句,最后回头执行try{}中的return语句。

public class Test1 {  
    public static int getA() {  
        int a = 5;  
        try {  
            a = 10;  
            System.out.println("try a = " + a);  
            return a; // try块中的return  
        } finally {  
            a = 20;  
            System.out.println("finally a =" + a);  
            // 注意:finally块不能改变try块中的返回值  
        }  
    }  


    public static void main(String[] args) {  
        int a = getA();  
        System.out.println("result a =" + a);  
    }  
}  


// 输出结果:
// try a = 10  
// finally a =20  
// result a =10

分析:

在Java中,finally块中的代码不会阻止trycatch块中的return语句执行,但finally块中的代码会在return语句之前执行(在返回值被确定之后,但在方法真正退出之前)。

然而,由于finally块不能改变trycatch块中已确定的返回值(除非是通过抛出异常),所以实际上返回的是trycatch块中计算得到的值。

不过,为了展示流程,我们可以这样写代码,但要知道finally块不能直接“回头”执行return语句。

2. 如果catch{}中没有return语句,则在执行完catch{}中的代码之后就执行finally{}中的语句,最后直接结束程序,并不会回到try{}中执行它的return语句(因为没有异常,不会进入catch块)。

public class Test2 {  
    public static int getA() {  
        int a = 5;  
        try {  
            a = 10 / 0; // 除以零 故意制造异常  
            return a; // 这行不会执行  
        } catch (ArithmeticException e) {  
            a = 15;  
            System.out.println("catch a = " + a);  
            // 没有return语句  
        } finally {  
            a = 20;  
            System.out.println("finally a =" + a);  
        }  
        // 假设方法最后有一个默认的return值  
        return 0;  
    }  


    public static void main(String[] args) {  
        int a = getA();  
        System.out.println("result a =" + a);  
    }  
}  


// 输出结果:
// catch a = 15  
// finally a =20  
// result a =0


3. 如果catch{}中含有return语句,则在执行完catch{}中的return的前一语句时直接进入finally{}中执行代码,但finally块中的代码不会改变catch块中已确定的返回值。

public class Test3 {  
    public static int getA() {  
        int a = 5;  
        try {  
            a = 10 / 0; // 故意制造异常  
            return a; // 这行不会执行  
        } catch (ArithmeticException e) {  
            a = 15;  
            System.out.println("catch a = " + a);  
            return a; // catch块中的return  
        } finally {  
            a = 20;  
            System.out.println("finally a =" + a);  
            // 注意:finally块不会改变catch块中的返回值  
        }  
        // 这部分代码不会执行  
    }  
  
    public static void main(String[] args) {  
        int a = getA();  
        System.out.println("result a =" + a);  
    }  
}  
  
// 输出结果:
// catch a = 15  
// finally a =20  
// result a =15

4. 如果finally中有return,那么最后的结果一定是finally中的return结果(不管有没有异常)。

public class Test4 {  
    public static int getA() {  
        int a = 5;  
        try {  
            a = 10;  
            System.out.println("try a = " + a);  
            return a; // try块中的return,但会被finally中的return覆盖  
        } catch (Exception e){
          a = 15;
          System.out.println("catch a = " + a);
          return a; // catch块中的return,但同样会被finally中的return覆盖
        } finally {
          a = 20;
          System.out.println("finally a =" + a);
          return a; // finally块中的return,这会覆盖try和catch中的return
        }
      }
      
    public static void main(String[] args) {  
          int a = getA();  
          System.out.println("result a =" + a);  
    }
}
    
      
// 输出结果:
// try a = 10
// finally a =20
// result a =20