finally代码块一定会执行吗
bmj

起因

同事发来两段代码,问我分别执行的结果是多少?

第一段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Demo1 {
public static void main(String[] args) {
Person p1 = people();
System.out.println(p1.age); // 执行结果是多少?
}
public static class Person {
int age;
}
public static Person people() {
Person p = new Person();
try {
p.age = 12;
return p;
} catch (Exception e) {
return null;
} finally {
p.age = 20;
}
}
}

第二段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Demo2 {
public static void main(String[] args) {
int s = people2();
System.out.println(s); // 执行结果是多少?
}
public static int people2() {
int i = 12;
try {
i = 15;
return i;
} catch (Exception e) {
return 0;
} finally {
i = 20;
}
}
}

猜想

第一段代码是new了一个对象,执行完try里的代码再执行finally里的代码,会修改引用对象中的age值,变成20,再return。所以猜想最终结果为20.

第二段代码不是对象了,而是直接修改了int的值,也不是引用地址了,try中变为15后可能就会直接执行return了。所以猜想结果为15.


执行

我将代码输入编辑器执行,结果:

  • 第一段代码结果:20
  • 第二段代码结果:15

蒙对了哈哈!


研究

当然是百度了。。。查阅网上的博客后,才知道finally块在某些情况下是不会执行的:

  • 在正常try能全部执行的情况下,finally都会执行,而程序还没执行到try,则finally不一定执行。
  • 对于基本数据类型,在try中return,在finally执行前会把结果暂存起来,即使在finally中有修改也以try中保存的值为准,但如果是引用类型,修改的属性会以finally修改后的为准。
  • 如果try/finally都有return,直接返回finally中的return。

根据上面的结论,就能够理解为什么第二段代码执行的结果是15而不是20了。


测试

根据结论,我又尝试了另外一种情况。根据第一段代码我们知道了,引用对象的属性即使try中有return,也会执行finally中的赋值操作改变属性值,那么如果在finally中new一个新的对象并赋值,结果又会是多少呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Demo3 {
public static void main(String[] args) {
Person p1 = people();
System.out.println(p1.age); // 执行结果又是多少?
}
public static class Person {
int age;
public Person(int age) {
this.age = age;
}
}
public static Person people() {
Person p = new Person(12);
try {
return p;
} catch (Exception e) {
return null;
} finally {
p = new Person(15);
}
}
}

结果是不会执行finally,输出结果:12。

这里返回了对象的引用,而并非像之前的代码修改了引用对象中的属性,所以直接返回了try中的p。当然如果在finally中 return p ,结果可以根据之前的结论得出:15。


参考

关于finally

 Comments