1. 当try{}
有return
语句,finally{}
有return
语句
1.1 代码示例
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);
}
}
1.2 编译,运行:
D:\JavaProject\demo15>javac TestFinally.java
D:\JavaProject\demo15>java TestFinally
execute finally1
3
1.3 总结:
-
如果在
try{}
语句块中有return
语句,而finally{}
语句块中没有return
语句时,finally{}
块中的代码在return
语句前执行。因为:由于程序执行
return
语句就意味着结束对当前函数的调用并跳出这个函数体,因此任何语句要执行都只能在return
前执行,因此finally
块里代码也是在return
前执行的。 -
如果在
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
块,最后再返回。
-
对于基本类型的数据,如果在
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
块,最后再返回。
- 对于引用类型的数据,定义该类型的数据变量时数据本身是存储在堆中的,在调用
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