当try、catch中有return时,finally中的代码会执行么?
今天,看到一个面试题:
try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
我们用代码来验证下:
public static void main(String[] args) { System.out.println("我是输出结果a:" + test1()); public static int test1() { int a = 5; try { System.out.println(a / 0); a = 10; } catch (ArithmeticException e) { System.out.println("我是catch中的a:" + a); return a = 20;// 程序执行到这时,a=20已经执行完,准备好返回结果了,发现有finally,则在去执行finally } finally { System.out.println("我是finally中未重定义的a:" + a); a = 30; System.out.println("我是finally中重定义过的a:" + a); } return a; }
运行结果:
1 我是catch中的a:5 2 我是finally中未重定义的a:20 3 我是finally中重定义过的a:30 4 我是输出结果a:20
从结果中可看出:即使catch中return了,finally中的代码还是会执行。但是有个问题,明明结果显示,经过finally代码的执行,a已经是30了,返回结果为什么还是20?
我们再执行另外代码:
1 public static void main(String[] args) { 2 System.out.println("我是输出结果a:" + test1()); 3 4 } 5 6 public static int test1() { 7 int a = 5; 8 try { 9 System.out.println(a / 0); 10 a = 10; 11 } catch (ArithmeticException e) { 12 System.out.println("我是catch中的a:" + a); 13 return a = 20;// 程序执行到这时,a=20已经执行完,准备好返回结果了,发现有finally,则在去执行finally 14 } finally { 15 System.out.println("我是finally中未重定义的a:" + a); 16 a = 30; 17 System.out.println("我是finally中重定义过的a:" + a); 18 return a = 30; 19 } 20 }
运行结果:
1 我是catch中的a:5 2 我是finally中未重定义的a:20 3 我是finally中重定义过的a:30 4 我是输出结果a:30
我们会发现,如果finally中有return,结果会根据finally中的结果返回,如果finally中没有return,结果会按照catch的结果返回,但是不管怎么样,都是会执行finally的代码。
前面的例子是基本类型的,那我们看下引用类型是不是也这样:
1 public static User getName1(){ 2 User user = null; 3 try { 4 user = new User("张三"); 5 throw new Exception(); 6 } catch (Exception e) { 7 user = new User("李四"); 8 return user; 9 } finally { 10 user = new User("王五"); 11 //return user; 12 } 13 }
结果
User [name=李四]
再试下其他:
1 public static User getName1(){ 2 User user = null; 3 try { 4 user = new User("张三"); 5 throw new Exception(); 6 } catch (Exception e) { 7 user = new User("李四"); 8 return user; 9 } finally { 10 user = new User("王五"); 11 return user; 12 } 13 }
结果:
1 User [name=王五]
额。。。。。。引用类型类型好像也是这样的。
我们再看看:
1 public static User getName2(){ 2 User user = null; 3 try { 4 user = new User("张三"); 5 throw new Exception(); 6 } catch (Exception e) { 7 user.setName("李四"); 8 return user; 9 } finally { 10 user.setName("王五"); 11 //return user; 12 } 13 }
结果如下:
User [name=王五]
额。。。。好像不对啊,不应该是李四吗?
1 public static User getName2(){ 2 User user = null; 3 try { 4 user = new User("张三"); 5 throw new Exception(); 6 } catch (Exception e) { 7 user.setName("李四"); 8 return user; 9 } finally { 10 user.setName("王五"); 11 return user; 12 } 13 }
结果:
User [name=王五]
引用类型好像有问题啊。。。。
其实可以这么理解:执行完catch内的代码后,会把结果值暂时保存,然后执行finally中的代码,如果finally中没有return,则直接把保存的值返回。如果finally中有return,则值会被finally改变,再返回。
而如果finally中没有return,返回的值好像也有部分出乎我们的意料。可以这样理解吧,catch中的结果值会被final修饰,当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变
化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。
就那下面代码来说明:
1 User u1 = new User("张三"); 2 User u2 = new User("李四"); 3 final User u3 = u1; 4 u3 = u2;//这行代码会报编译错误 5 System.out.println(u3); 6 u1.setName("王五"); 7 System.out.println(u3);
第四行代码会报编译错误:The final local variable u3 cannot be assigned. It must be blank and not using a compound assignment
说明final修饰的不能改变引用对象,但是引用对象u1的值变化还是可以。
上面的代码执行下:
User [name=张三]
User [name=王五]
现在可以看出 上面的代码 user.setName("王五");和user = new User("王五"); 执行的结果为什么会不一样,因为setname改变的是引用所指向的对象的内容,是可以的。= new User("王五"); 是改变了引用指向,是不可以的。