Java編程思想讀書筆記——通過異常處理錯誤(二)

12.7 Java標準異常

Throwable可以表示任何作爲異常被拋出的類,其可分爲兩類對象:Error和Exception。

Error表示編譯時和系統錯誤,一般不需關心;
Exception表示可以被拋出的基本類型,通常關心該類型。

異常的名稱都是可以望文知意的。

12.7.1 特例:RuntimeException

運行時異常由Java虛擬機自動拋出,不必在異常說明中列出,在編譯時也不檢查這類異常,也無需捕獲這類異常。

12.8 使用finally進行清理

finally子句,無論try塊中是否拋出異常,finally子句中的代碼都會被執行。

try {
    // The guarded region: Dangerous activities
    // that might throw A, B or C
} catch(A a1) {
    // Handler for situation A
} catch(B b1) {
    // Handler for situation B
} catch(C c1) {
    // Handler for situation C
} finally {
    // Activities that happen every time
}
12.8.1 finally用來做什麼

把除內存之外的資源恢復到初始狀態,就需要用到finally子句。如:
1) 已經打開的文件或網絡連接;
2) 在屏幕上畫的圖形;
3) 外部世界的某個開關。

12.8.2 在return中使用finally

因爲finally子句總是會被執行,所以在一個方法中,可以從多個點返回,並且可以保證重要的清理工作仍舊會被執行。

package com.mzm.chapter12;

/**
 * Created by 蒙卓明 on 2017/10/22.
 */
public class MultipleReturns {

    public static void f(int i){
        System.out.println("Initialization that requires cleanup");
        try{
            System.out.println("Point 1");
            if(i == 1){
                return;
            }
            System.out.println("Point 2");
            if(i == 2){
                return;
            }
            System.out.println("Point 3");
            if(i == 3){
                return;
            }
            System.out.println("End");
            return;
        } finally {
            System.out.println("Performing cleanup");
        }
    }

    public static void main(String[] args){
        for(int i = 1; i <= 4; i++){
            f(i);
        }
    }
}
12.8.3 缺憾:異常丟失

在某些情況下使用finally子句,可使異常被忽略。

package com.mzm.chapter12;

/**
 * 
 */
public class LostMessage {

    void f() throws VeryImportantException {
        throw new VeryImportantException();
    }

    void dispose() throws HoHumException {
        throw new HoHumException();
    }

    public static void main(String[] args) throws HoHumException {
        try{
            LostMessage lm = new LostMessage();
            try{
                lm.f();
            } finally {
                lm.dispose();
            }
        }catch (Exception e) {
            System.out.println(e);
        }
    }
}

class VeryImportantException extends Exception{
    public String toString(){
        return "A very important exception!";
    }
}

class HoHumException extends Exception{
    public String toString(){
        return "A trivial exception";
    }
}

VeryImportantException消失,其被finally子句中的HoHumException所取代。

package com.mzm.chapter12;

/**
 * 丟失異常
 * 
 */
public class ExceptionSilencer {

    public static void main(String[] args){
        try{
            throw new RuntimeException();
        } finally {
            //異常被忽略
            return;
        }
    }
}

12.9 異常的限制

當覆蓋方法時,只能拋出在父類方法的異常說明中所列的異常,也可以不拋異常,只是不能拋出父類相應方法異常說明之外的異常。

針對構造器而言,子類的構造器的異常說明必須包含父類的構造器的異常說明,並且不能捕獲父類構造器拋出的異常。

不能基於異常說明來重載方法。

12.10 構造器

在構造器中出現異常的情況,不要再finally子句中執行清理工作。

package com.mzm.chapter12;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * Created by 蒙卓明 on 2017/10/28.
 */
public class InputFile {

    private BufferedReader in;

    public InputFile(String fname) throws FileNotFoundException {
        try {
            in = new BufferedReader(new FileReader(fname));
        } catch (FileNotFoundException e) {
            System.out.println("Could not open " + fname);
            throw e;
        } catch (Exception e) {
            try{
                in.close();
            } catch (IOException e1) {
                System.out.println("in.close() unsuccessful");
            }

            throw e;
        } finally {
            //不建議在此處執行清理工作,因爲文件未成功打開
        }
    }

    /**
     * 獲取文件的下一行
     * @return 文件的下一行內容的字符串
     */
    public String getLine() {
        String s;
        try{
            s = in.readLine();
        } catch (IOException e) {
            throw new RuntimeException("readLine() failed");
        }
        return s;
    }

    public void dispose() {
        try{
            in.close();
            System.out.println("dispose() successful");
        } catch (IOException e) {
            throw new RuntimeException("in.close() failed");
        }
    }
}

12.11 異常匹配

拋出異常時,異常系統會按照就近原則找出最近的處理程序。原則上再編寫代碼時,子異常類在前,父異常類在後。

12.12 其他可選方式

開發異常程序的初衷是爲了方便程序員處理錯誤。
異常處理的重要原則:只有在知道如何處理的情況下才捕獲異常。
異常處理的目標:將異常發生地點與異常處理代碼分離。

12.12.3 把異常傳遞給控制檯

即在main()方法上加上異常說明,但是此種方式不推薦。

12.12.4 把”被檢查的異常”轉換爲”不檢查的異常”

實際上就是異常轉型,將編譯時異常轉型成爲運行時異常。

try {
    // ... to do somrthing useful
} catch (IDontKonwWhatToDoWithThisCheckedException e) {
    throw new RuntimeException(e);
}

12.13 異常使用指南

1) 在知道如何處理的情況下才捕獲異常;
2) 解決問題並且重新調用產生異常的方法;
3) 進行少許修補,然後繞過異常發生的地方繼續執行;
4) 用別的數據進行計算,以代替方法預計會返回的值;
5) 把當前運行環境下能做的事情儘量做完,然後把相同的異常拋到更高層;
6) 把當前運行環境下能做的事情儘量做完,然後把不同的異常拋到更高層;
7) 終止程序;
8) 進行簡化;
9) 讓類庫和程序更安全。

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