理解
在进行try catch进行异常处理时,不管是否抛出了异常,也不管在finally之前是否有return语句,finall均必然会被执行,除非程序被关闭(可能是电脑断电,关机,代码使其退出等非正常情况)。
finally的执行
finally之前无return的情况
首先看一个简单的例子:
public static void main(String[] args) {
div();
}
public static void div(){
int x,y;
Scanner input = new Scanner(System.in);
try{
System.out.println("请输入被除数x:");
x = input.nextInt();
System.out.println("请输入除数y:");
y = input.nextInt();
System.out.println("x/y=:"+x/y);
System.out.println("try语句执行完毕了");
}catch (Exception e){//只要有异常就接收,不管算术异常还是输入异常
System.out.println("catch语句被执行了");
}finally {
System.out.println("finally语句被执行了");
}
}
测试上面代码的结果:
没有抛出异常的情况
抛出异常的情况
可以看到不管try语句块中是否抛出异常了,finally语句块中的内容均会被执行。
finally之前有return的情况
finally之前即使含有return语句,finally也会被执行。执行流程:
- 先计算返回值,并将返回值复制,等待返回;
- 执行finally代码块;
- 将之前的复制值返回出去。
这里举两个返回非引用类型和引用类型的例子。
4. 返回非引用类型
public static void main(String[] args) {
System.out.println(test());
}
public static int test(){
int i=10;
try{
return i;
}catch (Exception e){
return 0;
}finally {
i=20;
}
}
这段代码最终输出的是10。
- 返回引用类型
public static void main(String[] args) {
Person p=test();
System.out.println(p.age);
}
public static Person test(){
Person p = new Person();
p.age = 10;
try{
return p;
}catch (Exception e){
return null;
}finally {
p.age = 20;
}
}
在这种情况下,输出为20。
在上面两个例子中,当try块或catch中的return被执行时,不是立马就返回,而是先把要返回的值复制一份,准备返回,在还未返回之前,finally中的语句块会先被执行。
因为基本类型变量这些非引用类型的变量是在栈中存储的,返回值复制的就是它们的值,而引用类型的实例存储在了堆区,返回值复制的是堆区的地址,所以第一种情况虽然在finally中修改了 i 的值,但返回值依然是10,第二种情况返回的是地址,当在finally中修改了其指向的内存中的内容时,最终自然就输出了改变后的内容。
finally不被执行的情况
当程序被关闭(可能是电脑断电,关机,代码使其退出等非正常情况)时finally才不被执行。比如:
public static void main(String[] args) {
test();
}
public static void test(){
try{
System.exit(0);
}catch (Exception e){
}finally {
System.out.println("finally被执行了");
}
在这种情况下并没有输出"finally被执行了"的语句,说明此时finally 语句块未被执行。
总结
- 不管程序是否抛出异常,finally中的代码均会被执行;
- 不管try,catch中是否含有return,finally中的代码依然会被执行(注意返回值是引用类型和非引用类型的区别);
- 除非程序被退出,否则finally中的代码必然被执行;
- finlly代码块中不建议包含有return,不然可能提前返回,导致返回的值不是try catch中的值。