前几天,去一家公司面试,碰到一道面试题大致内容为:如果在try中存在return语句,那么finally中的语句是否会执行,如果会执行,那先后顺序又是怎样。
当时自己的解题思路是:坚信大学时候,java编程基础的一句话,finally中的语句一定会执行,所以我觉得finally中的语句一定会执行,而return语句会跳出当前方法,所以return语句应该在finally语句执行完毕以后,再执行,否则return跳出以后,finally中的东西肯定是没办法执行的。
于是我查了一些资料,总结了几个情况。
首先,return可以出现在try、catch、finally、以及方法的最后,由于return在finally中,需要使用@SuppressWarnings("finally"),也是不推荐的做法,所以可行的做法为下列四种.
1 return在try和函数的最后出现一次
2 return在catch和函数的最后出现一次
3 return在try和catch中出现
4. return在方法最后出现
1 /* 2 * Copyright 2008-2014 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.app.spring.test; 17 18 /** 19 * TestTryCatchReturn 20 * <h1>return可以出现在try、catch、finally、以及方法的最后</h1> 21 * <h1>由于return在finally中,需要使用@SuppressWarnings("finally"),也是不推荐的做法</h1> 22 * 所以可行的做法为下列四种 23 * <ul> 24 * <li>return在try和函数的最后出现一次</li> 25 * <li>return在catch和函数的最后出现一次</li> 26 * <li>return在try和catch中出现</li> 27 * <li>return在方法最后出现</li> 28 * </ul> 29 * @author 李长伟 30 * @version 1.0 创建时间 2015年7月27日 下午2:04:17 31 * 32 */ 33 public class TestTryCatchReturn { 34 35 /** 36 * try中有return,finally中没有return 37 * 先执行finally中的语句 38 * 然后再执行try中的return 39 * @return 40 */ 41 public static String testTryReturnFinally() { 42 try { 43 return " try返回 " ; 44 } catch (Exception e) { 45 e.printStackTrace(); 46 } finally { 47 System.out.println( " 执行finally " ); 48 } 49 return " 退出try catch返回 " ; 50 } 51 52 /** 53 * try和finally中均有return 54 * 先执行try中的语句 55 * 然后再执行finally中的语句 56 * 最后执行finally中的return语句 57 * @return 58 */ 59 @SuppressWarnings( " finally " ) 60 public static String testTryReturnFinallyReturn() { 61 try { 62 System.out.println( " 执行try " ); 63 return " try返回 " ; 64 } catch (Exception e) { 65 e.printStackTrace(); 66 } finally { 67 System.out.println( " 执行finally " ); 68 return " finally返回 " ; 69 } 70 } 71 72 /** 73 * try中有return,finally中没有return,且存在修改变量的值 74 * 先执行try中的语句,修改值,并且也会执行return语句中修改值的操作 75 * 然后再执行finally中的语句,修改值,但是如果finally中没有return语句的话 76 * finally的修改无法影响到try中的return的返回值 77 * @return 78 */ 79 public static String testTryReturnFinallyBasic() { 80 int i = 10 ; 81 try { 82 i += 10 ; 83 return " try返回 " + i; 84 } catch (Exception e) { 85 e.printStackTrace(); 86 } finally { 87 i -= 10 ; 88 System.out.println( " 执行finally " + i); 89 } 90 return " 退出try catch返回 " ; 91 } 92 93 /** 94 * try中有return,finally中没有return,且存在修改对象的值 95 * 先执行try中的语句,修改值,并且也会执行return语句中修改对象的操作 96 * 然后再执行finally中的语句,修改值,但是如果finally中没有return语句的话 97 * finally的修改可以影响到try中的return的返回值 98 * @return 99 */ 100 public static Num testTryReturnFinallyObject() { 101 Num num = new TestTryCatchReturn(). new Num(); 102 try { 103 num.i += 10 ; 104 System.out.println( " 执行try " + num.i); 105 return num; 106 } catch (Exception e) { 107 e.printStackTrace(); 108 } finally { 109 num.i -= 10 ; 110 System.out.println( " 执行finally " + num.i); 111 } 112 return num; 113 } 114 115 class Num { 116 private int i = 10 ; 117 } 118 119 public static void main(String[] args) { 120 System.out.println( " =========1============ " ); 121 System.out.println(testTryReturnFinally()); 122 System.out.println( " =========1============ " ); 123 System.out.println( " =========2============ " ); 124 System.out.println(testTryReturnFinallyReturn()); 125 System.out.println( " =========2============ " ); 126 System.out.println( " =========3============ " ); 127 System.out.println(testTryReturnFinallyBasic()); 128 System.out.println( " =========3============ " ); 129 System.out.println( " =========4============ " ); 130 System.out.println(testTryReturnFinallyObject().i); 131 System.out.println( " =========4============ " ); 132 } 133 } 134
执行结果如下
=========1============
执行finally
try返回
=========1============
=========2============
执行try
执行finally
finally返回
=========2============
=========3============
执行finally10
try返回20
=========3============
=========4============
执行try20
执行finally10
10
=========4============在上面的代码中我测试了4种情况,由于return出现在try或者catch中对于程序的执行结果是没有影响的,所以程序中并没有测试return在catch中的情况
return在try和方法的最后,看结果很容易看出,finally中的语句先执行了,try中return的语句最后执行,而方法最后面的return并没有执行,因为已经跳出方法体了
try和finally中均有return语句,try中的方法执行,但是return没有返回,然后执行finally里面的方法,最后执行finally中的return,try中的return不执行
这里的情况其实和1里面是一样的,只不过添加了一个变量的修改,从结果可以看出,catch里面对i进行了加10的操作,finally对i做了减10的操作,尽管在finally中打印的结果是10,但是最后方法的返回值依然是20,所以如果return在try和catch中,finally对变量的修改不会影响到方法最后的返回值
这里的情况和3类似,只不过把对基本类型变量的修改,变成了对象的修改,唯一的不同是finally的修改对于对象类型的变量会保留,并在返回值中体现
程序的结果,其实个人感觉还是有一些疑问,例如我也测试过直接在try中的return后面跟(i += 10)操作,发现这个操作其实是在finally之前执行的,只是跳出方法体这个操作是在finally之后执行的,所以如果把3的代码中对i的操作放在return后面,结果是一样的
还有一个问题是,尽管4中最后返回的num对象的i值受到了finally中代码的影响,但是如果返回的是String类型,结果依然是20
对于上面的疑问,还是需要对于Java虚拟机有一个深刻的理解以后才能更清楚
引用别人的一句话
对以上情况的分析,需要深入JVM虚拟机中程序执行时对CLR栈的操作情况,可以参考《深入Java虚拟机:JVM高级特性与最佳实践》一书。