Java異常處理中finally的執(zhí)行問題

一、前言

因?yàn)檫@次面試有問到一些同學(xué)finally的問題,發(fā)現(xiàn)自己這塊好像有點(diǎn)記不太清楚了,有的點(diǎn)可能還給人家說錯了,一度弄得場面有些尷尬。所以說這篇文章深入研究一下finally的執(zhí)行情況和返回值的情況。

二、finally一定會執(zhí)行嗎?

先給答案:肯定不是。

我們可以看兩種情況:

1.在執(zhí)行try塊之前直接return,我們發(fā)現(xiàn)finally塊是不會執(zhí)行的
public class TryCatchTest {

    private static int total() {
        int i = 11;
        if (i == 11) {
            return i;
        }
        try {
            System.out.println("執(zhí)行try");
        } finally {
            System.out.println("執(zhí)行finally");
        }
        return 0;
    }

    public static void main(String[] args) {
        System.out.println("執(zhí)行main:" + total());
    }
}
輸出結(jié)果:
執(zhí)行main:11
2.在執(zhí)行try塊之前制造一個錯誤,直接爆紅
public class TryCatchTest {

    private static int total() {
        return 1 / 0;
        try {
            System.out.println("執(zhí)行try");  //這行爆紅,原因就是無法訪問
        } finally {
            System.out.println("執(zhí)行finally");
        }
        return 0;
    }

    public static void main(String[] args) {
        System.out.println("執(zhí)行main:" + total());
    }
}

綜上我們看出,如果程序連try塊都執(zhí)行不到,那么finally塊自然就不會執(zhí)行到了。

不過這里有的同學(xué)就會問:如果執(zhí)行了try塊,finally塊一定會執(zhí)行嗎?
有的同學(xué)答案就是一定會,其實(shí)非然,看看下面的例子吧:

public class TryCatchTest {

    private static int total() {
        try {
            System.out.println("執(zhí)行try");
            System.exit(0);
        } catch (Exception e) {
            System.out.println("執(zhí)行catch");
        } finally {
            System.out.println("執(zhí)行finally");
        }
        return 0;
    }

    public static void main(String[] args) {
        System.out.println("執(zhí)行main:" + total());
    }
}
輸出結(jié)果:
執(zhí)行try

我們在執(zhí)行try塊之中退出jvm,就沒事了,都不執(zhí)行了。當(dāng)然這個情況是比較極端的,記住就行,沒事不要亂整這個。
最后總結(jié)一下:不管是給try塊中造了個異常,還是在try塊中進(jìn)行return,我們發(fā)現(xiàn)finally塊還是會執(zhí)行的。因?yàn)楫惓L幚碓O(shè)計(jì)初衷就是讓finally塊始終執(zhí)行。在下面的時機(jī)探討我們可以證明上面的總結(jié)。

三、finally執(zhí)行時機(jī)探討

首先看常規(guī)情況:

public class TryCatchTest {

    private static int total() {
        try {
            System.out.println("執(zhí)行try");
            return 11;
        } finally {
            System.out.println("執(zhí)行finally");
        }
    }

    public static void main(String[] args) {
        System.out.println("執(zhí)行main:" + total());
    }
}
輸出結(jié)果:
    執(zhí)行try
    執(zhí)行finally
    執(zhí)行main:11

分析一下,不難得出在這個例子中finally塊執(zhí)行在try塊的return之前。
我們給try塊中造一個異常:

public class TryCatchTest {

    private static int total() {
        try {
            System.out.println("執(zhí)行try");
            return 1 / 0;
        } catch (Exception e) {
            System.out.println("執(zhí)行catch");
            return 11;
        } finally {
            System.out.println("執(zhí)行finally");
        }
    }

    public static void main(String[] args) {
        System.out.println("執(zhí)行main:" + total());
    }
}   
輸出結(jié)果:
    執(zhí)行try
    執(zhí)行catch
    執(zhí)行finally
    執(zhí)行main:11

同樣的,finally執(zhí)行在catch塊return的執(zhí)行前。

四、finally塊中的返回值

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

看一個例子:

public class TryCatchTest {

    private static int total() {
        int i = 0;
        try {
            System.out.println("執(zhí)行try:" + i);
            return i;
        } finally {
            ++i;
            System.out.println("執(zhí)行finally:" + i);
        }
    }

    public static void main(String[] args) {
        System.out.println("執(zhí)行main:" + total());
    }
}
輸出結(jié)果:
執(zhí)行try:0
執(zhí)行finally:1
執(zhí)行main:0

如果看完前面分析,會發(fā)現(xiàn)跟想象的不太一樣。我們經(jīng)過前面的分析,finally塊的執(zhí)行時機(jī)應(yīng)該是return之前,那理論上我們應(yīng)該先++i使得i等于1,在執(zhí)行return i; 自然會返回1??墒墙Y(jié)果卻返回了0,這是因?yàn)?strong>Java程序會把try或者catch塊中的返回值保留,也就是暫時的確認(rèn)了返回值,然后再去執(zhí)行finally代碼塊中的語句。等到finally代碼塊執(zhí)行完畢后,如果finally塊中沒有返回值的話,就把之前保留的返回值返回出去。

2.finally中含有返回值

示例1:

public class TryCatchTest {

    private static int total() {
        try {
            System.out.println("執(zhí)行try");
            return 1;
        } finally {
            System.out.println("執(zhí)行finally");
            return 2;
        }
    }

    public static void main(String[] args) {
        System.out.println("執(zhí)行main:" + total());
    }
}
輸出結(jié)果:
執(zhí)行try
執(zhí)行finally
執(zhí)行main:2

示例2:

public class TryCatchTest {

    private static int total() {
        int i = 1;
        try {
            System.out.println("執(zhí)行try:" + i);
            return i;
        } finally {
            ++i;
            System.out.println("執(zhí)行finally:" + i);
            return i;
        }
    }

    public static void main(String[] args) {
        System.out.println("執(zhí)行main:" + total());
    }
}
輸出結(jié)果:
執(zhí)行try:1
執(zhí)行finally:2
執(zhí)行main:2

示例3:

public class TryCatchTest {

    private static int total() {
        int i = 1;
        try {
            System.out.println("執(zhí)行try:" + i);
        } finally {
            ++i;
            System.out.println("執(zhí)行finally:" + i);
        }
        return i;
    }

    public static void main(String[] args) {
        System.out.println("執(zhí)行main:" + total());
    }
}
執(zhí)行結(jié)果:
執(zhí)行try:1
執(zhí)行finally:2
執(zhí)行main:2

這三個示例都說明了一點(diǎn),在分析含有finally塊的方法返回值時,要對于return出現(xiàn)的地方進(jìn)行具體分析。在finally塊中進(jìn)行return操作的話,則方法整體的返回值就是finally塊中的return返回值。如果在finally塊之后的方法內(nèi)return,則return的值就是進(jìn)行完上面的操作后的return值。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容