一、引言
当try里面有return,finally里面也有return时会有怎么的结果呢?
二、代码
话不多说,直接用代码进行测试。测试代码如下,
public class FinallyTest {
private static final FinallyTest instance = new FinallyTest("instance");
/**
* @param value
*/
private FinallyTest(String value) {
super();
this.value = value;
}
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
/**
* <p>测试基本类型
* @return
*/
public int testReturnInt() {
int b = 60;
try {
System.out.println("testReturnInt() in try. b = " + b);
// throw new NullPointerException();
return b += 50;
} catch (Exception e) {
System.out.println("testReturnInt() in catch. b = " + b);
// return b +=100;
}finally {
System.out.println("finally before edit. b = " +b);
b = 2000;
System.out.println("finally after edit. b= " + b);
return b;
}
// System.out.println("out of finally");
// return b + 1000;
}
/**
* <p>测试对象
* @return
*/
public FinallyTest testReturnObj() {
FinallyTest demo = new FinallyTest("origin");
try {
System.out.println("testReturnObj() in try. value = " + demo.getValue());
return demo;
} catch (Exception e) {
System.out.println("testReturnObj() in catch. value = " + demo.getValue());
} finally {
System.out.println("finally before edit. value = " + demo.getValue());
demo.setValue("modified");
System.out.println("finally after edit. value = " + demo.getValue());
return demo;
}
// System.out.println("out of finally");
// return demo;
}
public static void main(String[] args) {
System.out.println("in main. int =" + instance.testReturnInt()+"\n*************");
System.out.println("in main. value = " + instance.testReturnObj().getValue());
}
}
注意:上面这种return的方式(即在finally里面加上return),在eclipse里面会出现"finally block does not complete normally"的警告,下文会对此作一个说明。这里因为要举例,仍然暂时这么写。
三、测试用例
把try,catch,finally的情况分为三种:
1.try和finally型(即上文中的代码):
try{
return a = xxx;
}catch(Exception e){
xxx
}finally{
return a = xxxx;
}
终端输出:
testReturnInt() in try. b = 60
finally before edit. b = 110
finally after edit. b= 2000
in main. int =2000
*************
testReturnObj() in try. value = origin
finally before edit. value = origin
finally after edit. value = modified
in main. value = modified
结论:不论是基本类型还是引用对象,finally里面的return都会覆盖try里的return,这种方式不推荐。
try{
xxx;
}catch(Exception e){
return a = xxx;
}finally{
return a = xxxx;
}
相应地把testReturnInt()和testReturnObj()的return移动到catch里面,其他不变:
/**
* <p>测试基本类型
* @return
*/
public int testReturnInt() {
int b = 60;
try {
System.out.println("testReturnInt() in try. b = " + b);
// throw new NullPointerException();
// return b += 50;
// return b+50;
} catch (Exception e) {
System.out.println("testReturnInt() in catch. b = " + b);
return b +=50;
}finally {
System.out.println("finally before edit. b = " +b);
b = 2000;
System.out.println("finally after edit. b= " + b);
return b;
}
// System.out.println("out of finally");
// return b + 1000;
}
/**
* <p>测试对象
* @return
*/
public FinallyTest testReturnObj() {
FinallyTest demo = new FinallyTest("origin");
try {
System.out.println("testReturnObj() in try. value = " + demo.getValue());
// throw new NullPointerException();
// return demo;
} catch (Exception e) {
System.out.println("testReturnObj() in catch. value = " + demo.getValue());
return demo;
} finally {
System.out.println("finally before edit. value = " + demo.getValue());
demo.setValue("modified");
System.out.println("finally after edit. value = " + demo.getValue());
return demo;
}
// System.out.println("out of finally");
// return demo;
}
终端输出:
testReturnInt() in try. b = 60
finally before edit. b = 60
finally after edit. b= 2000
in main. int =2000
*************
testReturnObj() in try. value = origin
finally before edit. value = origin
finally after edit. value = modified
in main. value = modified
可以看到,由于没有异常,所以不会走catch分支,因此基本类型的值在finally before edit处不变,而引用对象的值由于是在finally里中set,因此仍然发生了变化。
3.try,catch,finally型
try{
xxx;
return a = xxx;
}catch(Exception e){
return a = xxx;
}finally{
return a = xxxx;
}
修改testReturnInt()和testReturnObj()如下:,通过传入不同的参数来决定是否走catch分支:
/**
* <p>
* 测试基本类型
*
* @return
*/
public int testReturnInt(int i) {
int b = 60;
try {
System.out.println("testReturnInt() in try. b = " + b);
if (i == -1) {
throw new NullPointerException();
} else {
return b += 50;
}
// return b+50;
} catch (Exception e) {
System.out.println("testReturnInt() in catch. b = " + b);
return b += 50;
} finally {
System.out.println("finally before edit. b = " + b);
b = 2000;
System.out.println("finally after edit. b= " + b);
return b;
}
// System.out.println("out of finally");
// return b + 1000;
}
这里基本上是对上述情况1和情况2的结合。不再给出具体的终端输出,结论仍然和情况1和情况2类似,即fianlly里面的return会对前面的return(不论是try还是catch分支进行覆盖)。
四、细心的同学应该会发现,其实我们还少了一种情况:
try{
xxx;
return a = xxx;
}catch(Exception e){
a=xxx;
}finally{
xxx;
a = xxxx;
}
System.out.println("out of finally");
a=xxx;
return a;
代码修改如下:
/**
* <p>
* 测试基本类型
*
* @return
*/
public int testReturnInt(int i) {
int b = 60;
try {
System.out.println("testReturnInt() in try. b = " + b);
if (i == -1) {
throw new NullPointerException();
}
return b += 50;
} catch (Exception e) {
System.out.println("testReturnInt() in catch. b = " + b);
// return b += 50;
} finally {
System.out.println("finally before edit. b = " + b);
b = 2000;
System.out.println("finally after edit. b= " + b);
// return b;
}
System.out.println("out of finally");
return b;
}
/**
* <p>
* 测试对象
*
* @return
*/
public FinallyTest testReturnObj(Object object) {
FinallyTest demo = new FinallyTest("origin");
try {
System.out.println("testReturnObj() in try. value = "
+ demo.getValue());
if (object == null) {
throw new NullPointerException();
}
return demo;
} catch (Exception e) {
System.out.println("testReturnObj() in catch. value = "
+ demo.getValue());
// return demo;
} finally {
System.out.println("finally before edit. value = "
+ demo.getValue());
demo.setValue("modified");
System.out
.println("finally after edit. value = " + demo.getValue());
// return demo;
}
System.out.println("out of finally");
demo.setValue("out of finally");
return demo;
}
public static void main(String[] args) {
System.out.println("in main. int =" + instance.testReturnInt(0)
+ "\n*************");
System.out.println("in main. value = "
+ instance.testReturnObj(new Object()).getValue());
}
终端输出:
testReturnInt() in try. b = 60
finally before edit. b = 110
finally after edit. b= 2000
in main. int =110
*************
testReturnObj() in try. value = origin
finally before edit. value = origin
finally after edit. value = modified
in main. value = modified
正常情况下会执行
try中的return,finally中的代码也会执行,但是finally外面的代码不会执行。
另外值得注意的是,基本类别的值在finally中发生了变化(对应输出中的:finally after edit. b= 2000),但是最终返回到main中的值仍然是try中的return
,即finally中的对基本类类型的修改是无效的(即对调用方是无效的);然而finally中对引用对象的修改却是有效的。
出现异常时会执行finally外面的return。这里不再作截图,读者有兴趣可以自行测试。
可见这种情况下a的值最多有可能在四个地方被改变,程序极易出现混乱,可读性很差,因此极其不推荐。
四、结论
终上,finally有return时,finally里面的return会覆盖原来的数据,而且也会修改原来的对象引用(基本类型数据不变----除非在finally之后有return语句)。所以,为了避免混乱,建议不要在finally里面写return。一般采用如下形式:
try{
xxx;
a=xxx;
return a;
}catch(Exception e){
xxx;
a=xxx;
return a;
}finally{
xxx;
}
或者统一在最后作return
try{
xxx;
a=xxx;
}catch(Exception e){
xxx;
a=xxx;
}finally{
xxx;
}
return a;
即finally里面不要作return(如非必要也尽量不要对返回的数据作修改),只作一些必要的关闭资源的工作。