三种可能不执行finally代码块的情况
- 在try代码块之外产生异常或者返回下是不会执行finally代码块的
- 执行try代码块时候退出了JVM虚拟机
- 在子线程执行try代码块或者catch代码块时候突然关闭了线程,也可能不执行finally代码块
- 突然断电了也可能

package simple;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        // 强制在try块中退出JVM也不会执行finally代码块,代码执行结果是不执行finally代码块
        // System.out.println("return value of test(): " + testExit());
        // 在try代码块之前返回或者抛异常都是不会执行finally代码块,执行结果是不执行finally代码块
        // System.out.println("return value of test(): " + test());

        // 子线程执行try代码块时候突然关闭线程了,也可能不会执行finally代码块,我的试验情况是会指定,但是不会保证一定执行。
        myThread thread = testThread();
        thread.start();
        Thread.sleep(1000);
        thread.isRunning = false;
        System.out.println("main exit");
    }

    static class myThread extends Thread {
        public boolean isRunning = true;

        @Override
        public void run() {
            super.run();
            System.out.println(Thread.currentThread().getName() + "\t begin running");
            try {
                while (isRunning) {
                    System.out.println("running");
                    // int i = 11 / 0;
                }
                if (isRunning == false) {
                    Thread.sleep(1000);
                }
                System.out.println(Thread.currentThread().getName() + "\t exit running");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                System.out.println("子线程");
            }
        };
    }

    public static myThread testThread() {

        return new myThread();

    }

    /**
     * 测试在try块中退出JVM
     * 
     * @return
     */
    public static int testExit() {
        int i = 1;

        try {
            System.out.println("try block");
            System.exit(0);
            return i;
        } finally {
            System.out.println("finally block");
        }
    }

    /**
     * 测试在try块之外抛异常或者返回
     * 
     * @return
     */
    public static int test() {
        int i = 1;

        // if (i == 1)
        // return 0;
        System.out.println("the previous statement of try block");
        i = i / 0;

        try {
            System.out.println("try block");
            return i;
        } finally {
            System.out.println("finally block");
        }
    }

}

关于finally代码块一定会执行的情况:

只有与 finally 相对应的 try 语句块得到执行的情况下,finally 语句块才会执行。不管 try 语句块正常结束还是异常结束,finally 语句块是保证要执行的。
如果 try 语句块正常结束,那么在 try 语句块中的语句都执行完之后,再执行 finally 语句块。如果 try 中有控制转移语句(return、break、continue)呢?那 finally 语句块是在try语句块中return控制转移语句之前执行

如果 try 语句块异常结束,应该先去相应的 catch 块做异常处理,然后执行 finally 语句块。同样的问题,如果 catch 语句块中包含控制转移语句呢? finally 语句块是在这些控制转移语句之前,还是之后执行呢?我们给出实例代码。
代码执行结果 说明了 finally 语句块在 catch 语句块中的 return 语句之前执行

public class Test { 
 public static void main(String[] args) {  
 System.out.println("reture value of test() : " + test()); 
     } 

 public static int test(){ 
 int i = 1; 

 try {  
 System.out.println("try block");  
             i = 1 / 0; 
 return 1;  
 }catch (Exception e){ 
 System.out.println("exception block"); 
 return 2; 
 }finally {  
 System.out.println("finally block");  
         } 
     } 
 }

综上 finally 语句块是在 try 或者 catch 中的 return 语句之前执行的。更加一般的说法是,finally 语句块应该是在控制转移语句之前执行,控制转移语句除了 return 外,还有 breakcontinue。另外,throw 语句也属于控制转移语句。虽然 return、throw、break 和 continue 都是控制转移语句,但是它们之间是有区别的。其中 return 和 throw 把程序控制权转交给它们的调用者(invoker),而 break 和 continue 的控制权是在当前方法内转移。请大家先记住它们的区别。

参考文章:
IBM

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐