Java Puzzlers(4)異常之謎

週末了,有時間更新一下。週末好象也沒什麼特別,除了多睡點和看看書之外,無事可做,可憐的單身生涯。

異常,複雜的話題了。

一。首先看看下面這個例子,到底返回true還是false呢?還是根本編譯不通過:

public class Indecisive {
    public static void main(String[] args) {
        System.out.println(decision());
    }

    static boolean decision() {
        try {
           return true;
        } finally {
            return false;
        }
    }
}

答案是false,finaly語句塊總是在程序控制權從try塊離開時開始執行,無論try語句塊中是以正常方式或者意外行爲結束。當try塊與finaly塊都以意外方式結束,整個try..finaly的意外結束的原因將與finaly語句塊意外結束的原因相同,即try塊意外結束的原因將被拋棄。對於finaly的使用,需要記住:

每一個finaly語句塊都應該被正常結束,除非拋出非受控異常。在finaly語句塊中不應該使用break,continue,return或者throw來退出,不應當讓受控異常傳播到finaly之外。

等等,我們再來看個例子,下面的finaly塊會被執行嗎??

public class HelloGoodbye {
    public static void main(String[] args) {
        try {
            System.out.println("Hello world");
            System.exit(0);
        } finally {
            System.out.println("Goodbye world");
        }
    }
}

很抱歉,它只打印:Hello World,finaly語句並沒有被執行,這是爲何?這是因爲System.exit方法將立刻終止當前程序的所有線程,使得finaly塊根本沒機會被調用。System.exit執行兩步操作,首先就是停止當前所有線程,其次就是在關閉VM之前執行Shut down Hook(關閉掛鉤)。如果我們希望在VM關閉之前執行一些操作,這些操作應該在Runtime.addShutDownHook上註冊,因此,上面的程序可以修改爲:

public class HelloGoodbye {
    public static void main(String[] args) {
  
       System.out.println("Hello world");
       Runtime.getRuntime().addShutdownHook(
               new Thread(){
           public void run(){
                System.out.println("Goodbye world");
           }
       });
       System.exit(0);
    }
}

 

二。來看看一些不可思議的程序。

第一個程序:

import java.io.IOException;

public class Arcane1 {
    public static void main(String[] args) {
        try {
            System.out.println("Hello world");
        } catch(IOException e) {
            System.out.println("I've never seen println fail!");
        }
    }
}

試着編譯下,sorry,不能通過。報錯:

在相應的try語句主體中不能拋出異常java.io.IOException

錯誤信息已經很明顯地告訴我們原因了,System.out.println方法並不能拋出受控異常IOException。這在JAVA語言規範中已經有描述,如果catch所捕捉的受控異常在try塊裏並不能被拋出,這將是一個編譯期錯誤!

第2個程序:

public class Arcane2 {
    public static void main(String[] args) {
        try {
        } catch(Exception e) {
            System.out.println("This can't happen");
        }
    }
}

編譯竟然通過了,這不是跟我們第一個程序得到的結論有矛盾??這又是因爲JAVA語言規範所決定的,捕獲Exception或者Throwable的catch語句都是合法,不管他們的try塊語句的內容是什麼。特例,特例^_^

第3個程序,有點長了,首先定義3個接口:

interface Type1 {
    void f() throws CloneNotSupportedException;
}

interface Type2 {
    void f() throws InterruptedException;
}

interface Type3 extends Type1, Type2 {
}

接口Type3繼承Type1,Type2(JAVA中接口是可以多重繼承的),Type1,Type2的f()方法各拋出一個受控異常。接着看:

public class Arcane3 implements Type3 {
    public void f() {
        System.out.println("Hello world");
    }

    public static void main(String[] args) {
        Type3 t3 = new Arcane3();
        t3.f();
    }
}

編譯通過,打印Hello World!可是我明明聲明瞭兩個受控異常啊,怎麼實現類都不用處理了??不是要放在一個try..catch塊裏面纔行??原因就在於一個方法可以拋出的受控異常的集合是它所適用所有類型(即父類型,此例中的Type1,Type2)聲明要拋出的受控異常的交集,而不是並集!

 

三。初始化與異常。構造函數必須聲明其實例初始化操作中會拋出的所有受控異常。類中值域的初始化操作是在調用構造函數之前發生的。不要濫用異常,比如使用異常去控制循環,應該只爲異常條件而使用異常。

四。刪除類,書中的謎題44,我不能完全理解,待續,如有朋友有好的見解,最好共享下。

五。以一個看似會無限循環的遞歸程序結尾,其實因爲JVM的棧的深度有限,此程序總會終結,可時間恐怕要在你我骨灰已經歷N個物質循環之後:

public class Workout {
    public static void main(String[] args) {
        workHard();
        System.out.println("It's nap time.");
    }

    private static void workHard() {
        try {
            workHard();
        } finally {
            workHard();
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章