1. 程式人生 > >_092_Java_finally中使用return會吃掉catch中丟擲的異常

_092_Java_finally中使用return會吃掉catch中丟擲的異常

轉自,感謝作者的無私分享。

如果在finally中使用return會吃掉catch中丟擲的異常,也會吃掉try或者catch中的return。

如果在finally中使用throw會吃掉catch中丟擲的異常,也會吃掉try或者catch中的return。

看例子:

public class TestException {  

    public TestException() {  

    }  


    boolean testEx() throws Exception {  

        boolean ret = true;  

        try {  

            ret = testEx1();  

        } catch (Exception e) {  

            System.out.println("testEx, catch exception");  

            ret = false;  

            throw e;  

        } finally {  

            System.out.println("testEx, finally; return value=" + ret);  

            return ret;  

        }  

    }  


    boolean testEx1() throws Exception {  

        boolean ret = true;  

        try {  

            ret = testEx2();  

            if (!ret) {  

                return false;  

            }  

            System.out.println("testEx1, at the end of try");  

            return ret;  

        } catch (Exception e) {  

            System.out.println("testEx1, catch exception");  

            ret = false;  

            throw e;  

        } finally {  

            System.out.println("testEx1, finally; return value=" + ret);  

            return ret;  

        }  

    }  


    boolean testEx2() throws Exception {  

        boolean ret = true;  

        try {  

            int b = 12;  

            int c;  

            for (int i = 2; i >= -2; i--) {  

                c = b / i;  

                System.out.println("i=" + i);  

            }  

            return true;  

        } catch (Exception e) {  

            System.out.println("testEx2, catch exception");  

            ret = false;  

            throw e;  

        } finally {  

            System.out.println("testEx2, finally; return value=" + ret);  

            return ret;  

        }  

    }  

  
    public static void main(String[] args) {  

        TestException testException1 = new TestException();  

        try {  

            testException1.testEx();  

        } catch (Exception e) {  

            e.printStackTrace();  

        }  

    }  

}  

執行結果:

i=2 i=1 testEx2, catch exception testEx2, finally; return value=false testEx1, finally; return value=false testEx, finally; return value=false

有點奇怪,下層方法丟擲的異常竟然沒有被捕獲。

如果把return和throw放在一起,直接會提示錯誤。"Unreachable statement"(無法被執行).

然而finally卻可以成功騙過編譯器讓兩者並存(是不是可以算是編譯器的一個小bug呢),結果是後執行的會覆蓋前者。finally如果有return會覆蓋catch裡的throw,同樣如果finally裡有throw會覆蓋catch裡的return。

進而如果catch裡和finally都有return finally中的return會覆蓋catch中的。throw也是如此。

這樣就好理解一些了,retrun和throw都是使程式跳出當前程式的方法,自然就是衝突的。如果非要跳出兩次那麼後者會覆蓋前者。

在《java程式設計思想》中也有類似的例子,放在這裡一起討論。

“9.6.2 缺點:丟失的違例 一般情況下,Java的違例實施方案都顯得十分出色。不幸的是,它依然存在一個缺點。儘管違例指出程式裡存在一個危機,而且絕不應忽略,但一個違例仍有可能簡單地“丟失”。在採用finally從句的一種特殊配置下,便有可能發生這種情況”

class VeryImportantException extends Exception{

public String toString(){

return "A very important exception";

}

}


class HoHumException extends Exception{

public String toString() {

return "A trivial exception";

}

}

public class LostMessage {

void f() throws VeryImportantException{

throw new VeryImportantException();

}


void dispose() throws HoHumException{

throw new HoHumException();

}


public static void main(String[] args) throws Exception{

LostMessage lm = new LostMessage();

try{

lm.f();

}finally {

lm.dispose();

}

}

}

輸出:

Exception in thread "main" A trivial exception at com.test.exception.LostMessage.dispose(LostMessage.java:24) at com.test.exception.LostMessage.main(LostMessage.java:32)  

“這是一項相當嚴重的缺陷,因為它意味著一個違例可能完全丟失。而且就象前例演示的那樣,這種丟失顯得非常“自然”,很難被人查出蛛絲馬跡。而與此相反,C++裡如果第二個違例在第一個違例得到控制前產生,就會被當作一個嚴重的程式設計錯誤處理。或許Java以後的版本會糾正這個問題(上述結果是用Java 1.1生成的)。”