微信公众号:Misout的博客
如有问题或建议,请留言
一、问题
从10月份协助领导不断面试招人,其中一个问题是关于finally的问题。finally是否一定执行?try代码块和finally代码块中如果都有return语句,谁先执行,是否都会执行?
。然而让我意外的是,很多人压根不清楚,非常模糊这个知识点,而且工作经验也很长。下面我们就来看看,finally的一些细节,为大家扫扫盲。
二、finally代码块一定会执行吗?
答案当然是否定的。原因显而易见,在如下的情况下,finally代码块不会执行。
- 在try代码块之前,程序出现异常,不会执行到finally代码块。
- 在try代码块之前,程序返回,不会执行finally代码块。
- 在try代码块中,如果主动执行
System.exit(0)
语句,不会执行finally代码块。 - 在没执行到finally代码块之前,突然JVM异常退出,例如断电,finally不会执行。
关于try中return后的返回值问题
代码示例
// 方法返回值是3 or 4?
public int finallyCase() {
int i = 1;
try {
i = 3;
System.out.println("try block,i="+i);
return i;
} finally {
i = 4;
System.out.println("finally block,i=" + i);
}
}
请回答输出结果?结果如下:
try block,i=3
finally block,i=4
方法返回值:3
为什么返回值是3而不是4?是不是出于你的意外?而且finally代码块中语句的确在try代码块return i
之前得到执行了,finally代码块中的i也确实变成了4,可是为什么方法返回值仍然是3呢?
通俗的说就是:JVM会把try或者catch代码块中的返回值保留,再来执行finally代码块中的语句,等到finally代码块执行完毕之后,再把之前保留的返回值给返回出去。本质上是由JVM在执行指令过程中的导致的。想弄懂具体原因,请阅读你真的知道finally吗?(二)
换个方式来问你:关于try中return后的返回值问题
在上一个章节示例中,你是否已经知道返回值问题。关于此问题,我们继续看一个变种示例:
// 在finally方法中多了一个return语句,返回值是3 or 4?
public int finallyCase() {
int i = 1;
try {
i = 3;
System.out.println("try block,i="+i);
return i;
} finally {
i = 4;
System.out.println("finally block,i=" + i);
return i;
}
}
请回答输出结果?结果如下:
try block,i=3
finally block,i=4
方法返回值:4
为什么现在是4?前面不是说在try中i的值会暂存吗?
但这里请注意,finally代码块是在try中return之前执行。i变成了4,然后直接return了,所以try中的return语句实际是没有被执行的。因此返回值为4。
引用类型-try中return后的返回值问题
前面我们已经研究了基本数据类型try和finally中return返回值的问题,下面我们再来看看引用类型的返回值问题,又会有哪些不同呢?
// 返回的user对象,姓名是u1还是u2
private static User test1() {
User user = new User("u1");
try {
return user;
} catch (Exception e) {
e.printStackTrace();
} finally {
user = new User("u2");
}
return null;
}
// 返回的user对象,姓名是u1还是u2
private static User test2() {
User user = new User("u1");
try {
return user;
} catch (Exception e) {
e.printStackTrace();
} finally {
user.setName("u2");
}
return null;
}
请问上面两个方法分别执行后,user对象的姓名值是多少?
答案
test1()方法:u1
test2()方法:u2
是不是又会令你百思不得其解?
原因其实和上面非常相似。对于引用类型,在try执行return之前,会暂存一份对象的引用,finally执行完后,将暂存的引用直接返回,所以test1方法中,虽然new出了一个新的User对象,但try中暂存的还是u1的对象,所以结果为u1。而test2方法中finally直接给对象的属性赋值,改变的并非对象的引用,所以返回的对象姓名为u2。
结论
- 在正常try能全部执行的情况下,finally都会执行,而程序还没执行到try,则finally不一定执行;
- 对于基本数据类型,在try中return,在finally执行前会把结果暂存起来,即使在finally中有修改也以try中保存的值为准,但如果是引用类型,修改的属性会以finally修改后的为准;
- 如果try/finally都有return,直接返回finally中的return。
网友评论