【Java疑难杂症】有return的情况下try catch finally的执行顺序

简介:   有这样一个问题,异常处理大家应该都不陌生,类似如下代码: 1 public class Test { 2 public static void main(String[] args) { 3 int d1 = 0; 4 int d2 =...

  有这样一个问题,异常处理大家应该都不陌生,类似如下代码:

 1 public class Test {
 2     public static void main(String[] args) {
 3         int d1 = 0;
 4         int d2 = 1;
 5         try {
 6             d2--;
 7             d1 = 1 / d2;
 8             System.out.println("try");
 9         }catch (Exception e){
10             System.out.println("Catch An Exception.");
11         }finally {
12             System.out.println("finally");
13         }
14     }
15 }

  运行到第7行的时候,会出现算术异常,try语句块捕获到这个异常,然后开始执行catch语句块中的内容,最后执行,finally语句块中的内容,因此输出如下:

Catch An Exception.
finally

  但是,如果try,catch,finally语句中有return的时候,会怎样呢?

  我们都知道,finally语句块是不论如何都会执行的,那三个块中的return,会先返回谁呢?我们来进行一下测试:

public class Test {
    public static void main(String[] args) {
        int i = Test.getReturn();
        System.out.println(i);

    }

    public static int getReturn(){
        int a = 0;
        int d1 = 0;
        int d2 = 1;
        try {
      //try语句块中没有发生异常 a
= 10; d1 = 1 / d2; return a; }catch (Exception e){ a = 20; System.out.println("Catch An Exception."); return a; }finally { a = 30; System.out.println("finally"); return a; } } }

  这里的try语句块中没有发生异常,那么执行顺序如何呢?在try中的return是直接返回吗?finally的return该怎样处理呢?先让我们看一下结果:

finally
30

  结果是执行完成finally语句块之后,使用的是finally语句块中的a,而不是try语句块中的a。

  那如果try中出现异常呢?我们改动一下:

public class Test {
    public static void main(String[] args) {
        int i = getReturn();
        System.out.println(i);

    }

    public static int getReturn(){
        int a = 0;
        int d1 = 0;
        int d2 = 1;
        try {
            a = 10;
            d1 = 1 / (--d2);
            return a;
        }catch (Exception e){
            a = 20;
            System.out.println("Catch An Exception.");
            return a;
        }finally {
            a = 30;
            System.out.println("finally");
            return a;
        }
    }
}

  好的,现在try中出现了算术异常,catch语句块将被执行,然后再执行finally语句块,这样的话返回结果如何呢?

Catch An Exception.
finally
30

  还是返回30,也就是finally中a的值

  如果去掉finally中的return会怎样?

public class Test {
    public static void main(String[] args) {
        int i = getReturn();
        System.out.println(i);

    }

    public static int getReturn(){
        int a = 0;
        int d1 = 0;
        int d2 = 1;
        try {
            a = 10;
            d1 = 1 / (--d2);
            return a;
        }catch (Exception e){
            a = 20;
            System.out.println("Catch An Exception.");
            return a;
        }finally {
            a = 30;
            System.out.println("finally");
            //return a;
        }
    }
}

  输出如下:

Catch An Exception.
finally
20

  返回的是catch语句块中的a。先执行catch语句块中的代码,finally语句虽然执行了,a的值应该也被修改成30了,但实际返回的却是20,。

  我们再来做一个测试,把catch和finally语句块中的return都注释掉,来看看返回情况:

public class Test {
    public static void main(String[] args) {
        int i = getReturn();
        System.out.println(i);

    }

    public static int getReturn(){
        int a = 0;
        int d1 = 0;
        int d2 = 1;
        try {
            a = 10;
            d1 = 1 / (d2);
            return a;
        }catch (Exception e){
            a = 20;
            System.out.println("Catch An Exception.");
            //return a;
        }finally {
            a = 30;
            System.out.println("finally");
            //return a;
        }
        return a;
    }
}

  输出如下:

finally
10

  所以finally中虽然修改了a的值,但实际返回的是修改之前的值。也就是相当于程序先用一个瓶子将try中的return的值装起来,后面不管finally如果修改a的值,返回值都不会变,但这只是因为返回的是基本数据类型,如果是引用类型,还是有点区别的,来看个栗子。

  先声明一个Stu类:

public class Stu {
    String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

  测试一下:

public class Test {
    public static void main(String[] args) {
        Stu stu = getReturn();
        System.out.println(stu.getName());

    }

    public static Stu getReturn(){
        Stu stu = new Stu();
        int d1 = 0;
        int d2 = 1;
        try {
            stu.setName("1");
            d1 = 1 / (d2);
            return stu;
        }catch (Exception e){
            stu.setName("2");
            System.out.println("Catch An Exception.");
        }finally {
            stu.setName("3");
            System.out.println("finally");
        }
        return stu;
    }
}

  输出如下:

finally
3

  所以你看,现在还是变成了finally中的修改值,所以瓶子里装的只是变量中的内容,只能保证这个内容不会变,如果是引用变量,变量中存储的是引用对象的地址,finally中对引用对象的修改还是会影响到返回对象的。

  所以结论其实很简单,try,catch,finally语句块的return的优先级由低到高,先执行try中return之前的语句,如果遇到异常,则执行catch语句中return之前的代码,最后执行finally语句块,finally语句块中如果有return,那么程序就会提前返回,如果没有,则返回catch语句块中的return,如果没有遇到异常,则直接执行finally中的语句块,再看finally语句块中是否有return来决定返回结果。

  结论:
  1、不管是否出现异常,finally块中的代码都会执行;
  2、当try和catch中有return时,finally仍然会执行,finally中的return优先级大于catch大于try;
  3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
  4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。

真正重要的东西,用眼睛是看不见的。
相关文章
|
10天前
|
Java
java构造方法,构造代码块,静态代码块的执行顺序
本文介绍了Java中构造方法、构造代码块和静态代码块的执行顺序。静态代码块用`static`声明,在JVM加载类时执行一次;构造代码块在每次创建对象时执行,先于构造方法;构造方法用于对象初始化,创建对象时调用。示例代码展示了这三者的输出顺序,并解释了它们的区别和应用场景。
|
13天前
|
设计模式 Java
Java中的finally一定会被执行吗
在Java中,`finally`块通常会在正常情况下执行,但在特定异常情况下(如调用`System.exit()`、`Runtime.getRuntime().halt()`、死锁、掉电或JVM崩溃)则不会执行。此外,`System.exit()`会触发JVM关闭钩子,而`Runtime.getRuntime().halt()`则不会。面试时遇到疑问句,答案往往是“否定”的,符合这一逻辑。
Java中的finally一定会被执行吗
|
4月前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
123 2
|
4月前
|
Java 程序员 数据库连接
Java执行顺序大揭秘:静态块、非静态块和构造方法谁先谁后?
本文详细介绍了Java中的初始化块,包括静态初始化块和非静态初始化块的概念、执行顺序和实际应用场景。通过具体示例,帮助读者理解这两种初始化块的区别和使用场景,让面试官对你刮目相看。
56 0
Java执行顺序大揭秘:静态块、非静态块和构造方法谁先谁后?
|
5月前
|
存储 Java
[Java]面试官:你对异常处理了解多少,例如,finally中可以有return吗?
本文介绍了Java中`try...catch...finally`语句的使用细节及返回值问题,并探讨了JDK1.7引入的`try...with...resources`新特性,强调了异常处理机制及资源自动关闭的优势。
36 1
|
5月前
|
Java
java中父类方法return this.对象还是变量,子类去调用this.这个方法的问题
本文探讨了在Java中,当父类的方法返回`this`对象或变量时,子类调用该方法的行为,以及`this`关键字在不同类中调用方法时的指向问题。
37 0
java中父类方法return this.对象还是变量,子类去调用this.这个方法的问题
|
5月前
|
缓存 安全 Java
Java中 final、finally、finalize 有什么区别?
本文详细阐述了Java中`final`、`finally`和`finalize`的区别:`final`用于修饰类、方法和变量以表示不可变性;`finally`是用于确保在`try-catch`结构中无论是否发生异常都能执行的代码块;而`finalize`是`Object`类的方法,用于在对象被垃圾回收前执行清理工作,但在JDK 9中已被标记为弃用。
132 0
Java中 final、finally、finalize 有什么区别?
|
7月前
|
Java 数据安全/隐私保护
Java代码的执行顺序和构造方法
构造方法是类的一种特殊方法,用于初始化新对象。在 Java 中,每个类默认都有一个与类名同名的构造方法,无需返回类型。构造方法不能用 static、final、synchronized、abstract 或 native 修饰。它可以重载,通过不同的参数列表实现多种初始化方式。构造方法在对象实例化时自动调用,若未显式声明,默认提供一个无参构造方法。构造代码块和静态代码块分别用于对象和类的初始化,按特定顺序执行。
58 0
|
Java
Java中的return作用
Java中的return作用
153 0
Java中的return作用
|
Java
Java中Return的作用
其实Java提供return,是为了保持调用者与被调用者进行通信的关键。比如某个对象调用了一个方法,他需要根据这个方法不同的返回值进行不同的业务处理。如果没有return机制的话,那就只能进行单一的业务处理了,不存在多种情况了。返回值的意义就是保持方法的调用者与被调用者进行通信的关键,这和java中异常抛出的机制是一样的。下面跟你简单说说return的两种用法吧 retu
1522 0