Java 中的 finally 必定會被執行嗎?

不要因懼怕冒險而踟躕不前,而要爲創造偉大提供可能。面試

1、前言jvm


由於此次面試有問到一些同窗finally的問題,發現本身這塊好像有點記不太清楚了,有的點可能還給人家說錯了,一度弄得場面有些尷尬。因此說這篇文章深刻研究一下finally的執行狀況和返回值的狀況。設計

2、finally必定會執行嗎?

先給答案:確定不是。code

咱們能夠看兩種狀況:it

1.在執行try塊以前直接return,咱們發現finally塊是不會執行的
public class TryCatchTest {
    private static int total() {
        int i = 11;
        if (i == 11) {
            return i;
        }
        try {
            System.out.println("執行try");
        } finally {
            System.out.println("執行finally");
        }
        return 0;
    }
    public static void main(String[] args) {
        System.out.println("執行main:" + total());
    }
}

輸出結果:
執行main:11
複製代碼io

2.在執行try塊以前製造一個錯誤,直接爆紅
public class TryCatchTest {
    private static int total() {
        return 1 / 0;
        try {
            System.out.println("執行try");
        } finally {
            System.out.println("執行finally");
        }
        return 0;
    }
    public static void main(String[] args) {
        System.out.println("執行main:" + total());
    }
}

綜上咱們看出,若是程序連try塊都執行不到,那麼finally塊天然就不會執行到了class

不過這裏有的同窗就會問:若是執行了try塊,finally塊必定會執行嗎?有的同窗答案就是必定會,其實非然,看看下面的例子吧:變量

public class TryCatchTest {
    private static int total() {
        try {
            System.out.println("執行try");
            System.exit(0);
        } catch (Exception e) {
            System.out.println("執行catch");
        } finally {
            System.out.println("執行finally");
        }
        return 0;
    }
    public static void main(String[] args) {
        System.out.println("執行main:" + total());
    }
}

輸出結果:
執行try 程序

咱們在執行try塊之中退出jvm,就沒事了,都不執行了。固然這個狀況是比較極端的,記住就行,沒事不要亂整這個。最後總結一下:不論是給try塊中造了個異常,仍是在try塊中進行return,咱們發現finally塊仍是會執行的。由於異常處理設計初衷就是讓finally塊始終執行。這個總結在finally的執行時機獲得證實。方法

3、finally執行時機探討

首先看常規狀況:

public class TryCatchTest {
    private static int total() {
        try {
            System.out.println("執行try");
            return 11;
        } finally {
            System.out.println("執行finally");
        }
    }
    public static void main(String[] args) {
        System.out.println("執行main:" + total());
    }
}

輸出結果:

執行try  
執行finally  
執行main:11

分析一下,不可貴出在這個例子中finally塊執行在try塊的return以前。咱們給try塊中造一個異常:

public class TryCatchTest {
    private static int total() {
        try {
            System.out.println("執行try");
            return 1 / 0;
        } catch (Exception e) {
            System.out.println("執行catch");
            return 11;
        } finally {
            System.out.println("執行finally");
        }
    }
    public static void main(String[] args) {
        System.out.println("執行main:" + total());
    }
}

輸出結果:

執行try  
執行catch  
執行finally  
執行main:11

一樣的,finally執行在catch塊return的執行前

4、finally塊中的返回值

1.finally塊不含返回值,可是作改變變量值的操做

看一個例子:

public class TryCatchTest {
    private static int total() {
        int i = 0;
        try {
            System.out.println("執行try:" + i);
            return i;
        } finally {
            ++i;
            System.out.println("執行finally:" + i);
        }
    }
    public static void main(String[] args) {
        System.out.println("執行main:" + total());
    }
}

輸出結果:
執行try:0
執行finally:1
執行main:0

若是看完前面分析,會發現跟想象的不太同樣。咱們通過前面的分析,finally塊的執行時機應該是return以前,那理論上咱們應該先++i使得i等於1,在執行return i; 天然會返回1。

但是結果卻返回了0,這是由於Java程序會把try或者catch塊中的返回值保留,也就是暫時的確認了返回值,而後再去執行finally代碼塊中的語句。等到finally代碼塊執行完畢後,若是finally塊中沒有返回值的話,就把以前保留的返回值返回出去。

2.finally中含有返回值

示例1:

public class TryCatchTest {
    private static int total() {
        try {
            System.out.println("執行try");
            return 1;
        } finally {
            System.out.println("執行finally");
            return 2;
        }
    }
    public static void main(String[] args) {
        System.out.println("執行main:" + total());
    }
}

輸出結果:
執行try
執行finally
執行main:2


示例2:

public class TryCatchTest {
    private static int total() {
        int i = 1;
        try {
            System.out.println("執行try:" + i);
            return i;
        } finally {
            ++i;
            System.out.println("執行finally:" + i);
            return i;
        }
    }
    public static void main(String[] args) {
        System.out.println("執行main:" + total());
    }
}

輸出結果:
執行try:1
執行finally:2
執行main:2


示例3:

public class TryCatchTest {
    private static int total() {
        int i = 1;
        try {
            System.out.println("執行try:" + i);
        } finally {
            ++i;
            System.out.println("執行finally:" + i);
        }
        return i;
    }
    public static void main(String[] args) {
        System.out.println("執行main:" + total());
    }
}

執行結果:
執行try:1
執行finally:2
執行main:2

這三個示例都說明了一點,在分析含有finally塊的方法返回值時,要對於return出現的地方進行具體分析。在finally塊中進行return操做的話,則方法總體的返回值就是finally塊中的return返回值。若是在finally塊以後的方法內return,則return的值就是進行完上面的操做後的return值。

相關文章
相關標籤/搜索