1. 当try{}有return语句,finally{}有return语句
- 直接上程序
public class TestFinally
{
public static int testFinally1()
{
try{
return 1;
}catch(Exception e){
return 0;
}finally{
System.out.println("execute finally1");
return 3;
}
}
public static void main(String[] args)
{
int result = testFinally1();
System.out.println(result);
}
}
- 编译,运行:
D:\JavaProject\demo15>javac TestFinally.java
D:\JavaProject\demo15>java TestFinally
execute finally1
3
- 总结:
- (1)如果在try{}语句块中有return语句,而finally{}语句块中没有return语句时,finally{}块中的代码在return语句前执行。
- 因为:由于程序执行return语句就以为着结束对当前函数的调用并跳出这个函数体,因此任何语句要执行都只能在return前执行,因此finally块里代码也是在return前执行的。
- (2)如果在try{}语句块和finally语句块都有return语句时,finally语句块中的return语句将会覆盖函数中其他return语句。
2. finally{}中有修改return语句中的返回值
2.1 修改的返回值为基本数据类型
- 直接上程序
public class TestFinally
{
public static int testFinally2()
{
int result = 1;
try{
result = 2;
return result;//执行到此处,返回值被复制
}catch(Exception e){
return 0;
}finally{
result = 3;//改变result的值与复制result的值谁先谁后?
/*从执行结果来看,是复制result的值在先,修改result的值在后。
也就是在遇到return时,就对result进行了复制,然而,
前面讲到“finally块里代码也是在return前执行的”,
即使在return前面执行finally语句块,但是在执行finally语句块
时已经对返回值result进行了复制。*/
System.out.println("execute finally2");
}
public static void main(String[] args)
{
int resultVal = testFinally2();
System.out.println(resultVal);
}
}
- 编译,运行:
D:\JavaProject\demo15>javac TestFinally.java
D:\JavaProject\demo15>java TestFinally
execute finally2
2
- 总结:程序执行到return时首先将返回值存储到一个指定的位置,其次去执行finally块,最后再返回。
- (1)对于基本类型的数据,如果在finally块中没有return语句而存在修改返回值的语句时,在finally块中改变return的值对返回值没有任何影响。
- 因为:在方法中,定义的基本类型数据的变量都存储在栈中,当这个函数结束以后,其对应的栈就会被回收,此时在该方法体定义的这类变量将不存在了,因此返回时不是直接返回变量的值,而是复制一份,再返回。
- 本例方法testFinally2中调用return之前,先把result的值1存储在一个指定的位置,然后再去执行finally块中的代码,因此finally块中修改result的值不会影响到方法的返回结果。因此,在代码中的注释的猜想是正确的。
2.2 修改的返回值为引用类型
- 直接上程序:
public class TestFinally
{
public static StringBuffer testFinally3()
{
StringBuffer s = new StringBuffer("hello");
try{
return s;
}catch(Exception e){
return null;
}finally{
s.append(" world");
System.out.println("execute finally3");
}
}
public static void main(String[] args)
{
StringBuffer resultString = testFinally3();
System.out.println(resultString);
}
}
- 编译,运行:
D:\JavaProject\demo15>javac TestFinally.java
D:\JavaProject\demo15>java TestFinally
execute finally3
hello world
- 总结:程序执行到return时首先将返回值存储到一个指定的位置,其次去执行finally块,最后再返回。
- (2)对于引用类型的数据,定义该类型的数据变量时数据本身是存储在堆中的,在调用return之前首先把变量s的副本存储到一个指定的位置(s指向的是StringBuffer数据,这里并不是将s指向的数据存储到指定的位置,只是将“指针”s存到了其他地方,但还是指向的是堆内存的StringBuffer数据),由于s为引用类型,因此在finally块中修改s将会修改程序的返回结果。这一点从指针的角度更容易理解。
3. finally语句是不是一定会执行?答案:不一定会执行。
3.1 当程序在进入try语句之前就出现异常时,会直接结束,不会执行finally块中的语句的代码。
public class Test
{
public static void testFinally()
{
int i = 5/0;
try{
System.out.println("try block");
}catch (Exception e){
System.out.println("catch block");
}finally{
System.out.println("finally block");
}
}
public static void main(String[] args)
{
testFinally();
}
}
- 编译,运行:
D:\JavaProject\demo15>javac TestFinally.java
D:\JavaProject\demo15>java TestFinally
Exception in thread "main" java.lang.ArithmeticException: / by zero
at TestFinally.testFinally(TestFinally.java:5)
at TestFinally.main(TestFinally.java:16)
3.2 当程序在try块中强制退出时也不会去执行finally块中的代码。
public class Test
{
public static void testFinally()
{
try{
System.out.println("try block");
System.exit(0);
}catch (Exception e){
System.out.println("catch block");
}finally{
System.out.println("finally block");
}
}
public static void main(String[] args)
{
testFinally();
}
}
- 编译,运行:
D:\JavaProject\demo15>javac TestFinally.java
D:\JavaProject\demo15>java TestFinally
try block
参考:《Java程序员面试笔试宝典》