大家好,欢迎来到IT知识分享网。
深度解析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代码块之前就结束了myMethod()方法,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有了一个更深的了解了呢!
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/147425.html