return和finally的执行顺序有关问题
一、引言
当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分支进行覆盖)。
细心的同学应该会发现,其实我们还少了一种情况:
xxx;
return a = xxx;
}catch(Exception e){
xxx;
}finally{
xxx;
a = xxxx;
}
System.out.println("out of finally");
return a;
事实上,这种情况下,finally外面的return永远不会执行,out of finally也永远不会打印出来。但从语法完整性上来看,这个return a又是必不可少的,如果少了这一句,就会提示类似“This method must return a result of type int”的编译错误。而在这种情况下,基本类型的返回数据不会发生变化,即仍然返回110(try里面的值),而对象引用的数据却发生了变化 ,返回的对象value为modified。
四、结论
终上,finally有return时,finally里面的return会覆盖原来的数据,而且也会修改原来的对象引用(基本类型数据不变),所以,建议不要在finally里面写retun,一般写成如下形式,比较好一点:
try{ xxx; return a = xxx; }catch(Exception e){ xxx; return a = xxx; }finally{ xxx; }
即分别在try和catch里面作retun,finally里面不要作return(也不要对要返回的数据作修改),只作一些必要的关闭资源的工作