finally代码块是否一定会执行?

一、 首先在大家的印象中,无论程序是否出现异常,Finally代码块是一定会执行的。这个观点可能会让大家有些失望了,答案是否定的。接下来就让我来详细的给大家讲解一下吧。
案例1:

package com.test;
 
public class MyTest {
 
	public static void main(String[] args) {
 
		System.out.println("main 代码块中的执行结果为:" + myMethod());
	}
 
	public static int myMethod() {
 
		int i = 0;
		int[] num = { 1, 2, 3 };
 
		System.out.println(num[3]);
 
		try {
			System.out.println("try 代码块被执行!");
			return 0;
		} catch (Exception e) {
			System.out.println("catch 代码块被执行!");
			return 0;
		} finally {
			System.out.println("finally 代码块被执行!");
		}
 
	}
 
}

其执行结果为:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
	at com.test.MyTest.myMethod(MyTest.java:15)
	at com.test.MyTest.main(MyTest.java:7)

可以看到结果显示 数组下标越界,没有下标为3的这个索引,我们可以看到并没有执行finally代码块中的打印语句

案例2:

package com.test;
 
public class MyTest {
 
	public static void main(String[] args) {
 
		System.out.println("main 代码块中的执行结果为:" + myMethod());
	}
 
	public static int myMethod() {
 
		int i = 0;
		int[] num = { 1, 2, 3 };
 
		if (i == 0) {
		    return 0;
		}
 
		System.out.println(num[3]);
 
		try {
			System.out.println("try 代码块被执行!");
			return 0;
		} catch (Exception e) {
			System.out.println("catch 代码块被执行!");
			return 0;
		} finally {
			System.out.println("finally 代码块被执行!");
		}
 
	}
 
}

另外,当我们在myMethod()方法中添加如下这段

if (i == 0) {
    return 0;
}

在运行代码,其结果如下,也没有执行finally代码块中的打印语句

main 代码块中的执行结果为:0

通过以上例子可以看出,finally代码块中的打印语句都没有被执行,这是为什么呢?

这是因为这两个例子都在try代码块之前就结束了temp()方法,try代码块并没有得到执行,所以finally中的代码块也不会得到相应的执行。只有在try代码块得到执行的情况下,finally代码块才会得到执行。

二、那么问题又来了,是不是只要try代码块得到执行了,finally代码块才一定会执行呢?可能又会让你们失望了,答案是不一定会执行,这是为什么呢,请看如下的
案例3:

package com.test;
 
public class MyTest {
 
	public static void main(String[] args) {
 
		System.out.println("main 代码块中的执行结果为:" + myMethod());
	}
 
	public static int myMethod() {
 
		try {
			System.out.println("try 代码块被执行!");
 
			System.exit(0);
 
			return 0;
		} catch (Exception e) {
			System.out.println("catch 代码块被执行!");
			return 0;
		} finally {
			System.out.println("finally 代码块被执行!");
		}
 
	}
 
}

执行结果为:

try 代码块被执行!

可以看到只打印了try代码块中的语句,finally代码块中的语句并没有打印,这是因为System.exit(0),它表示退出当前Java虚拟机,一旦退出Java虚拟机,任何代码都不会再执行。

三、你们会说,写程序一般都不会写System.exit(0);来退出Java虚拟机,那么是不是不写System.exit(0);finally代码块就一定会得到执行呢?

可能还是会让你们失望了,答案时不一定的,这又是为什么?来看这段文字,估计你应该会明白一些。

如果当一个线程在执行 try 语句块或者 catch 语句块时被打断(interrupted)或者被终止(killed),与其相对应的 finally 语句块可能不会执行。还有更极端的情况,就是在线程运行 try 语句块或者 catch 语句块时,突然死机或者断电,finally 语句块肯定不会执行了。

四、下面来让我们讲解一下,再排除以上finally代码块得不到执行的情况外,finally代码块与try代码块和catch代码块的执行顺序,当try和catch代码块中有return语句时,又是一个什么样的情况。请看如下的
案例4:

package com.test;
 
public class MyTest {
 
	public static void main(String[] args) {
 
		System.out.println("main 代码块中的执行结果为:" + myMethod());
	}
 
	public static int myMethod() {
 
		int i = 6;
		try {
			System.out.println("try 代码块被执行!");
 
			// i = i/0;
 
			return 1;
		} catch (Exception e) {
			System.out.println("catch 代码块被执行!");
			return 2;
		} finally {
			System.out.println("finally 代码块被执行!");
		}
 
	}
 
}

执行结果为:

try 代码块被执行!
finally 代码块被执行!
main 代码块中的执行结果为:1

可以看到finally代码块中的打印语句在try代码块中的return 1; 语句之前被执行

当把 i = i/0; 前面的注释符去掉之后,其执行结果为

try 代码块被执行!
catch 代码块被执行!
finally 代码块被执行!
main 代码块中的执行结果为:2

可以看到finally代码块在catch代码块中的return 2; 语句之前被执行

五、 通过以上案例,是不是觉得自己对finally已经掌握颇深了呢?别急,还有一些是你不了解的,请听我来给你详细的讲解一下。请看如下的
案例5:

package com.test;
 
public class MyTest {
 
	public static void main(String[] args) {
 
		System.out.println("main 代码块中的执行结果为:" + myMethod());
	}
 
	@SuppressWarnings("finally")
	public static int myMethod() {
 
		try {
			System.out.println("try 代码块被执行!");
			return 1;
		} catch (Exception e) {
			System.out.println("catch 代码块被执行!");
			return 2;
		} finally {
			System.out.println("finally 代码块被执行!");
			return 3;
		}
 
	}
}

其执行结果为:

try 代码块被执行!
finally 代码块被执行!
main 代码块中的执行结果为:3

想必看了执行结果应该很容易理解,因为finally代码块要在try代码块中的 return 1; 语句之前执行,所以当执行到finally代码块中的return 3; 语句时,myMethod()方法就结束了,并返回一个3.

六、再来看一个案例,大家可以先不看执行结果,想一下它的执行结果会是什么样子的,请看如下的
案例6:

package com.test;
 
public class MyTest {
 
	public static void main(String[] args) {
 
		System.out.println("main 代码块中的执行结果为:" + myMethod());
	}
 
	public static int myMethod() {
 
		int i = 1;
		try {
 
			System.out.println("try 代码块被执行!");
			return i;
		} finally {
			++i;
			System.out.println("finally 代码块被执行!");
			System.out.println("finally 代码块中的i = " + i);
		}
 
	}
 
}

执行结果为:

try 代码块被执行!
finally 代码块被执行!
finally 代码块中的i = 2
main 代码块中的执行结果为:1

是不是觉得结果有点出乎意料,最后一句输出语句的执行结果应该为2,可为什么是1呢?而且finally代码块中的 ++i 语句也的确在try代码块中的 return i; 语句之前得到执行了,finally代码块中的 i 也确实变成了2,可是为什么main函数打印出来的结果却是1呢?

通俗的说就是:先会把try或者catch代码块中的返回值保留,再来执行finally代码块中的语句,等到finally代码块执行完毕之后,在把之前保留的返回值给返回出去。

请注意,对于前面这条规则(保留返回值),只适用于 return和throw语句,不适用于break和continue语句,因为它们根本就没有返回值。

这样就能够理解为什么打印的是1,而不是2了,这是因为try代码块中先会保留return返回的1,然后再去执行finally代码块中的++i,i的值虽然变成了2,可是保留的值还是1,没有变,所以等到finally代码块执行完毕之后,try代码块就会把保留值1给返回出去

七、有了上面的讲解,我们在来看一下下面的这几个案例

案例7:

package com.test;
 
public class MyTest {
 
	public static void main(String[] args) {
 
		System.out.println("main 代码块中的执行结果为:" + myMethod());
	}
 
	@SuppressWarnings("finally")
	public static int myMethod() {
 
		int i = 1;
		try {
 
			System.out.println("try 代码块被执行!");
 
		} finally {
			++i;
			System.out.println("finally 代码块被执行!");
			System.out.println("finally 代码块中的i = " + i);
			return i;
		}
 
	}
 
}

其执行结果为:

try 代码块被执行!
finally 代码块被执行!
finally 代码块中的i = 2
main 代码块中的执行结果为:2

案例8:

package com.test;
 
public class MyTest {
 
	public static void main(String[] args) {
 
		System.out.println("main 代码块中的执行结果为:" + myMethod());
	}
 
	public static int myMethod() {
 
		int i = 1;
		try {
 
			System.out.println("try 代码块被执行!");
			i = 3;
		} finally {
			++i;
			System.out.println("finally 代码块被执行!");
			System.out.println("finally 代码块中的i = " + i);
 
		}
 
		return i;
 
	}
 
}

其执行结果为:

try 代码块被执行!
finally 代码块被执行!
finally 代码块中的i = 4
main 代码块中的执行结果为:4

八、以上的两个案例都比较好理解,接下来看一下下面这个案例9,大家可以先不看执行结果,来想一下它的执行情况

package com.test;
 
public class MyTest {
 
	public static void main(String[] args) {
 
		System.out.println("main 代码块中的执行结果为:" + myMethod());
	}
 
	public static int myMethod() {
 
		try {
 
			System.out.println("try 代码块被执行!");
			return num();
		} finally {
 
			System.out.println("finally 代码块被执行!");
 
		}
 
	}
 
	public static int num() {
 
		System.out.println("num 代码块被执行!");
		return 2;
	}
 
}

其执行结果为:

try 代码块被执行!
num 代码块被执行!
finally 代码块被执行!
main 代码块中的执行结果为:2

是不是觉得很奇怪,num()方法中的打印语句居然在finally代码块中的打印语句之前被执行,而finally代码块的打印语句又在num()方法中的 return 2; 语句之前被打印,这又是为什么呢?

其实 return num(); 等同于下面这段代码

int sum = num();
return sum;

所以就会先打印num()方法中的语句,后打印finally代码块中的语句。

通过以上讲解,是不是对finally有了一个更深的了解了呢!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值