当前位置:主页 > 查看内容

Java 的 finally 代码块的代码一定会执行吗?

发布时间:2021-08-18 00:00| 位朋友查看

简介:一、背景 对于很多初学者而言 会想当然地认为 “finally 代码块一定会被执行” 因此我们可以看下面这个案例 public class Demo { ? ?public static void main(String[] args) { ? ? ? ?try { ? ? ? ? ? ?BufferedReader br new BufferedReader(new FileReade……

一、背景

对于很多初学者而言 会想当然地认为 “finally 代码块一定会被执行” 因此我们可以看下面这个案例


public class Demo {

? ?public static void main(String[] args) {

? ? ? ?try {

? ? ? ? ? ?BufferedReader br new BufferedReader(new FileReader( file.txt

? ? ? ? ? ?System.out.println(br.readLine());

? ? ? ? ? ?br.close();

? ? ? ?} catch (IOException e) {

? ? ? ? ? ?// 省略一些代码

? ? ? ?} finally {

? ? ? ? ? ?System.out.println( Exiting the program

? ? ? ?}

? ?}

}

问题是 该段代码 finally 的代码块一定会被执行吗 为什么


二、分析

通常实际编码时 捕获异常后会记录日志或者将异常抛出等 此时 finally 代码块一般肯定会被执行到。


那么如何才能不执行finally呢


于是我们想到 如果让虚拟机退出 问题不就解决了吗 (就是这么暴力)


因此填充代码


public class Demo {

? ?public static void main(String[] args) {

? ? ? ?try {

? ? ? ? ? ?BufferedReader br new BufferedReader(new FileReader( file.txt

? ? ? ? ? ?System.out.println(br.readLine());

? ? ? ? ? ?br.close();

? ? ? ?} catch (IOException e) {

? ? ? ? ? System.exit(2);

? ? ? ?} finally {

? ? ? ? ? ?System.out.println( Exiting the program

? ? ? ?}

? ?}

}

如果捕获到 IO异常 则会执行 ?虚拟机退出指令 则不会执行finally 代码块。


System#exit 的源码如下


? ?/**

? ? * Terminates the currently running Java Virtual Machine. The

? ? * argument serves as a status code; by convention, a nonzero status

? ? * code indicates abnormal termination.

? ? * p

? ? * This method calls the code exit /code method in class

? ? * code Runtime /code . This method never returns normally.

? ? * p

? ? * The call code System.exit(n) /code is effectively equivalent to

? ? * the call:

? ? * blockquote pre

? ? * Runtime.getRuntime().exit(n)

? ? * /pre /blockquote

? ? *

? ? * param ? ? ?status ? exit status.

? ? * throws ?SecurityException

? ? * ? ? ? ?if a security manager exists and its code checkExit /code

? ? * ? ? ? ?method doesn t allow exit with the specified status.

? ? * see ? ? ? ?java.lang.Runtime#exit(int)

? ? */

? ?public static void exit(int status) {

? ? ? ?Runtime.getRuntime().exit(status);

? ?}

通过注释我们可以了解到 当 status 为 非0 时 表示异常退出。


底层调用到 Runtime#exit


? ?/**

? ? * Terminates the currently running Java virtual machine by initiating its

? ? * shutdown sequence. ?This method never returns normally. ?The argument

? ? * serves as a status code; by convention, a nonzero status code indicates

? ? * abnormal termination.

? ? *

? ? * p The virtual machine s shutdown sequence consists of two phases. ?In

? ? * the first phase all registered { link #addShutdownHook shutdown hooks},

? ? * if any, are started in some unspecified order and allowed to run

? ? * concurrently until they finish. ?In the second phase all uninvoked

? ? * finalizers are run if { link #runFinalizersOnExit finalization-on-exit}

? ? * has been enabled. ?Once this is done the virtual machine { link #halt

? ? * halts}.

? ? *

? ? * p If this method is invoked after the virtual machine has begun its

? ? * shutdown sequence then if shutdown hooks are being run this method will

? ? * block indefinitely. ?If shutdown hooks have already been run and on-exit

? ? * finalization has been enabled then this method halts the virtual machine

? ? * with the given status code if the status is nonzero; otherwise, it

? ? * blocks indefinitely.

? ? *

? ? * p The tt { link System#exit(int) System.exit} /tt method is the

? ? * conventional and convenient means of invoking this method. p

? ? *

? ? * param ?status

? ? * ? ? ? ? Termination status. ?By convention, a nonzero status code

? ? * ? ? ? ? indicates abnormal termination.

? ? *

? ? * throws SecurityException

? ? * ? ? ? ? If a security manager is present and its tt { link

? ? * ? ? ? ? SecurityManager#checkExit checkExit} /tt method does not permit

? ? * ? ? ? ? exiting with the specified status

? ? *

? ? * see java.lang.SecurityException

? ? * see java.lang.SecurityManager#checkExit(int)

? ? * see #addShutdownHook

? ? * see #removeShutdownHook

? ? * see #runFinalizersOnExit

? ? * see #halt(int)

? ? */

? ?public void exit(int status) {

? ? ? ?SecurityManager security System.getSecurityManager();

? ? ? ?if (security ! null) {

? ? ? ? ? ?security.checkExit(status);

? ? ? ?}

? ? ? ?Shutdown.exit(status);

? ?}


三、延伸

同样的问题 请看下面代码片段


public class Demo {

? ?public static void main(String[] args) {

? ? ?// 一些代码

? ? ? ?try {

? ? ? ? ? ?BufferedReader br new BufferedReader(new FileReader( file.txt

? ? ? ? ? ?System.out.println(br.readLine());

? ? ? ? ? ?br.close();

? ? ? ?} catch (IOException e) {

? ? ? ? ? System.exit(2);

? ? ? ?} finally {

? ? ? ? ? ?System.out.println( Exiting the program

? ? ? ?}

? ?}

}

问题是 如果try 代码块部分发生IO异常 是否一定不会执行到 finally 代码块呢


what? ?上面不是说不会执行吗


我们再仔细看上面给出的 ?Runtime#exit 源码 可以发现 如果 SecurityManager 不为 null 则 会进行安全检查。


public void exit(int status) {

// 如果有securityManager , 则调用 checkExit函数

? ? ? ?SecurityManager security System.getSecurityManager();

? ? ? ?if (security ! null) {

? ? ? ? ? ?security.checkExit(status);

? ? ? ?}

// 检查通过后退出

? ? ? ?Shutdown.exit(status);

? ?}

安全检查通过才会执行 ? Shutdown#exit 执行最终的虚拟机退出。


因此如果我们可以修改 SecurityManager 如果检查退出时抛出异常 那么在 执行 ?System.exit(2) 时就会发生异常 最终依然会执行到 finally代码块。


public class Demo {

? ?public static void main(String[] args) {

? ? ? ?// 修改 SecurityManager

? ? ? ?System.setSecurityManager(new SecurityManager() {

? ? ? ? ? ? Override

? ? ? ? ? ?public void checkExit(int status) {

? ? ? ? ? ? ? ?throw new SecurityException( 不允许退出

? ? ? ? ? ?}

? ? ? ?});

? ? ? ?try {

? ? ? ? ? ?BufferedReader br new BufferedReader(new FileReader( file.txt

? ? ? ? ? ?System.out.println(br.readLine());

? ? ? ? ? ?br.close();

? ? ? ?} catch (IOException e) {

? ? ? ? ? ?System.exit(2);

? ? ? ?} finally {

? ? ? ? ? ?System.out.println( Exiting the program

? ? ? ?}

? ?}

}


四、总结

学习时一定要抱着不满足的心态 这样才能有机会学的更加深入 理解地更好。





本文转自网络,原文链接:https://developer.aliyun.com/article/787275
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!
上一篇:SpringBoot 代码混淆方案 ProGuard 下一篇:没有了

推荐图文


随机推荐