有这样一个问题,异常处理大家应该都不陌生,类似如下代码:
1 public class Test { 2 public static void main(String[] args) { 3 int d1 = 0; 4 int d2 = 1; 5 try { 6 d2--; 7 d1 = 1 / d2; 8 System.out.println("try"); 9 }catch (Exception e){ 10 System.out.println("Catch An Exception."); 11 }finally { 12 System.out.println("finally"); 13 } 14 } 15 }
运行到第7行的时候,会出现算术异常,try语句块捕获到这个异常,然后开始执行catch语句块中的内容,最后执行,finally语句块中的内容,因此输出如下:
Catch An Exception. finally
但是,如果try,catch,finally语句中有return的时候,会怎样呢?
我们都知道,finally语句块是不论如何都会执行的,那三个块中的return,会先返回谁呢?我们来进行一下测试:
1 public class Test { 2 public static void main(String[] args) { 3 int i = Test.getReturn(); 4 System.out.println(i); 5 6 } 7 8 public static int getReturn(){ 9 int a = 0; 10 int d1 = 0; 11 int d2 = 1; 12 try { 13 //try语句块中没有发生异常 14 a = 10; 15 d1 = 1 / d2; 16 return a; 17 }catch (Exception e){ 18 a = 20; 19 System.out.println("Catch An Exception."); 20 return a; 21 }finally { 22 a = 30; 23 System.out.println("finally"); 24 return a; 25 } 26 } 27 }
这里的try语句块中没有发生异常,那么执行顺序如何呢?在try中的return是直接返回吗?finally的return该怎样处理呢?先让我们看一下结果:
finally
30
结果是执行完成finally语句块之后,使用的是finally语句块中的a,而不是try语句块中的a。
那如果try中出现异常呢?我们改动一下:
1 public class Test { 2 public static void main(String[] args) { 3 int i = getReturn(); 4 System.out.println(i); 5 6 } 7 8 public static int getReturn(){ 9 int a = 0; 10 int d1 = 0; 11 int d2 = 1; 12 try { 13 a = 10; 14 d1 = 1 / (--d2); 15 return a; 16 }catch (Exception e){ 17 a = 20; 18 System.out.println("Catch An Exception."); 19 return a; 20 }finally { 21 a = 30; 22 System.out.println("finally"); 23 return a; 24 } 25 } 26 }
好的,现在try中出现了算术异常,catch语句块将被执行,然后再执行finally语句块,这样的话返回结果如何呢?
Catch An Exception. finally 30
还是返回30,也就是finally中a的值
如果去掉finally中的return会怎样?
1 public class Test { 2 public static void main(String[] args) { 3 int i = getReturn(); 4 System.out.println(i); 5 6 } 7 8 public static int getReturn(){ 9 int a = 0; 10 int d1 = 0; 11 int d2 = 1; 12 try { 13 a = 10; 14 d1 = 1 / (--d2); 15 return a; 16 }catch (Exception e){ 17 a = 20; 18 System.out.println("Catch An Exception."); 19 return a; 20 }finally { 21 a = 30; 22 System.out.println("finally"); 23 //return a; 24 } 25 } 26 }
输出如下:
Catch An Exception. finally 20
返回的是catch语句块中的a。先执行catch语句块中的代码,finally语句虽然执行了,a的值应该也被修改成30了,但实际返回的却是20,。
我们再来做一个测试,把catch和finally语句块中的return都注释掉,来看看返回情况:
1 public class Test { 2 public static void main(String[] args) { 3 int i = getReturn(); 4 System.out.println(i); 5 6 } 7 8 public static int getReturn(){ 9 int a = 0; 10 int d1 = 0; 11 int d2 = 1; 12 try { 13 a = 10; 14 d1 = 1 / (d2); 15 return a; 16 }catch (Exception e){ 17 a = 20; 18 System.out.println("Catch An Exception."); 19 //return a; 20 }finally { 21 a = 30; 22 System.out.println("finally"); 23 //return a; 24 } 25 return a; 26 } 27 }
输出如下:
finally
10
所以finally中虽然修改了a的值,但实际返回的是修改之前的值。也就是相当于程序先用一个瓶子将try中的return的值装起来,后面不管finally如果修改a的值,返回值都不会变,但这只是因为返回的是基本数据类型,如果是引用类型,还是有点区别的,来看个栗子。
先声明一个Stu类:
1 public class Stu { 2 String name; 3 4 public String getName() { 5 return name; 6 } 7 8 public void setName(String name) { 9 this.name = name; 10 } 11 12 }
测试一下:
1 public class Test { 2 public static void main(String[] args) { 3 Stu stu = getReturn(); 4 System.out.println(stu.getName()); 5 6 } 7 8 public static Stu getReturn(){ 9 Stu stu = new Stu(); 10 int d1 = 0; 11 int d2 = 1; 12 try { 13 stu.setName("1"); 14 d1 = 1 / (d2); 15 return stu; 16 }catch (Exception e){ 17 stu.setName("2"); 18 System.out.println("Catch An Exception."); 19 }finally { 20 stu.setName("3"); 21 System.out.println("finally"); 22 } 23 return stu; 24 } 25 }
输出如下:
1 finally 2 3
所以你看,现在还是变成了finally中的修改值,所以瓶子里装的只是变量中的内容,只能保证这个内容不会变,如果是引用变量,变量中存储的是引用对象的地址,finally中对引用对象的修改还是会影响到返回对象的。
所以结论其实很简单,try,catch,finally语句块的return的优先级由低到高,先执行try中return之前的语句,如果遇到异常,则执行catch语句中return之前的代码,最后执行finally语句块,finally语句块中如果有return,那么程序就会提前返回,如果没有,则返回catch语句块中的return,如果没有遇到异常,则直接执行finally中的语句块,再看finally语句块中是否有return来决定返回结果。
结论:
1、不管是否出现异常,finally块中的代码都会执行;
2、当try和catch中有return时,finally仍然会执行,finally中的return优先级大于catch大于try;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
备注:此文转载自 http://www.cnblogs.com/mfrank/p/7895660.html