天天看點

《Java 核心技術 卷1》 筆記 第11章 異常、日志、斷言和調試

《Java 核心技術 卷1》 筆記 第11章 異常、日志、斷言和調試

出現不可預計的問題時,需要進行如下處理:

  1. 報告錯誤
  2. 儲存操作結果
  3. 允許使用者退出

本章解決的問題:

  • 驗證程式正确性
  • 記錄程式錯誤
  • 調試技巧

11.1 處理異常

程式出現錯誤時應該:

  • 傳回安全狀态,能讓使用者執行其他指令
  • 允許使用者儲存所有操作結果,并能夠終止程式

程式錯誤的關注點:

  1. 使用者輸入錯誤
  1. 不遵循程式要求,文法不正确,程式代碼應該檢查,如果沒有檢查,會出現錯誤(遇到過,沒檢查到,提示不友好使用者投訴的)
  1. 裝置錯誤
  1. 硬體不一定能夠使用,比如列印機關上了,沒紙了(這個處理好IO問題不大)
  1. 實體限制
  1. 磁盤滿了(遇到過,資料庫太大把磁盤占滿,搬資料庫)
  1. 代碼錯誤
  1. 傳回了錯誤的答案,或者錯誤的調用了其他方法(必然遇到過T T)

11.1.1 異常分類

Throwable下,分為Error和Exception

Exception下,又分爲IOException和RuntimeException

Error: Java運作時的内部錯誤和資源耗盡錯誤。這種錯誤通常是系統當機級别的,處理起來時間較長。(比如沒有磁盤空間了)通常在代碼層面無法處理這種錯誤。

RuntimeException: 程式本身沒有問題,IO錯誤等

常見的運作時異常:

  1. 數組越界
  2. 空指針
  3. 類型轉換錯誤

檢查異常:

  1. 錯誤URL
  2. 反射異常
  3. 讀取超出檔案尾部的資料

是以非運作時錯誤,一定是編碼問題

11.1.2 聲明已檢查異常

無法處理的情況,Java方法可以抛出一個異常,告訴編譯器要傳回什麼值,如果沒有值,則傳回發生的錯誤。

抛出異常的情況:

(1)調用抛出異常的方法

(2)運作過程中發生錯誤,抛出已檢查異常

(3)程式錯誤,提供不應該提供的數值,a[-1]=0 會報越界異常

(4)Java 虛拟機和運作庫異常

前兩種必須捕獲,不捕獲可能當機

抛出異常的方式:

Class MyAnimation{

Pubic Image loadImage(String s) throw EOFException,MalformedURLException{}

}

異常處理方式:

捕獲:進行處理,展示給使用者

抛出:交給上一層級處理

不處理:不可控的Error,或者使用規則限制,不産生額外的異常

特殊要求:

子類異常範圍,不能超出父類異常範圍

11.1.3 如何抛出異常

假設IO讀取資料時不完整,可考慮抛出IOException, API 提議抛出 EOFException

基本格式:

public [傳回值] 方法名(參數清單) 抛出清單{

        throw new XXException();

}      

11.1.4 建立異常類

有時候,标準異常描述并不能做到清楚具體,或者無法具體定位異常原因,為了進一步了解是程式中的哪一段出現異常,可考慮建立自己的異常類(個人覺得一個是名稱識别,另外異常文字之類的可以做特殊處理,讓它列印到log對應級别上而非直接輸出)。

class FileFormatException extends IOException{
  public FileFormatException(){}
  public FileFormatException(String gripe){
    super(gripe);
  }
}      

然後就可以像IOException一樣使用這種異常

public class Main {
    public static void main(String[] args) throws FontFormatException {
        Main solution = new Main();

        solution.test(1);

    }

    private void test(int num) throws FontFormatException {
        if(num==1)
            throw new FontFormatException("test");
    }
}      

不傳之密,異常處理工具,保留一定字數的異常資訊(資料庫存儲大小是有限的):

public class ErrorUtil {
    public static String exceptionStr(Exception e, int length) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        e.printStackTrace(new PrintStream(baos));
        String exception = baos.toString();
        
        String regEx = "Caused by:(.*)";
        Pattern pat = Pattern.compile(regEx);
        Matcher mat = pat.matcher(exception);
        boolean rs = mat.find();
        if (rs) {
            if (mat.group(1).length() > length) {
                return mat.group(1).substring(0, length);
            } else {
                return mat.group(1);
            }
        } else {
            if (exception.length() > length) {
                return exception.substring(0, length);
            } else {
                return exception;
            }
        }
    }
    
    public static String exceptionStr(Exception e){
        return exceptionStr(e,800);
    }
    
    public static String getAllException(Exception e){
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        e.printStackTrace(new PrintStream(baos));
        String exception = baos.toString();
        String regEx = "Caused by:(.*)";
        Pattern pat = Pattern.compile(regEx);
        Matcher mat = pat.matcher(exception);
        boolean rs = mat.find();
        if (rs) {
             return mat.group(1);
        } else {
             return exception;
        }
    }
}      

結合:

public class Main {
    public static void main(String[] args) {
        Main solution = new Main();

        try {
            solution.test(1);
        } catch (FontFormatException e) {
            System.out.println(ErrorUtil.getAllException(e));
        }

    }

    private void test(int num) throws FontFormatException {
        if(num==1)
            throw new FontFormatException("test");
    }
}      
《Java 核心技術 卷1》 筆記 第11章 異常、日志、斷言和調試