[core java學習筆記][第十一章異常斷言日誌調試]

來源:互聯網
上載者:User

標籤:資訊   with   animation   enable   checked   學習   time   iter   super   

第11章 異常,斷言,日誌,調試
  • 處理錯誤
  • 捕獲異常
  • 使用異常機制的技巧
  • 使用斷言
  • 日誌
  • 測試技巧
  • GUI程式排錯技巧
  • 使用調試器
11.1 處理錯誤11.1.1異常分類
  • 都繼承自Throwable類
  • 分成Error和Exception

    • Error類

      描寫敘述了Java運行時系統的內部錯誤和資源耗盡錯誤。

      應用程式不應該拋出此種類型的錯誤。假設出現了這樣的內部錯誤。除了通告給使用者,並儘力使程式安全地終止外,再也無能為力

    • Exception階層:最需關注的

      • RuntimeException 程式錯誤導致的異常

        • 錯誤的類型轉換
        • 數組訪問越界
        • 訪問null 指標
      • 不是派生於RuntimeException 因為像I/O錯誤,程式本身沒有問題導致的異常

        • 試圖在檔案尾部讀取後面資料
        • 試圖開啟一個不存在的檔案
        • 試圖依據給定的字串尋找Class對象。而那個字串表示的類不存在
  • java語言規範 派生於 Error類或RuntimeException類的全部異常稱為未檢查(unchecked)異常,全部其它異常稱為已檢查(checked)異常。

11.1.2 聲明已檢查異常
  • 下面四種情況自己編寫方法時。須要拋出異常

    • 調用一個拋出checked異常的方法。比如,FileInputStream構造器
    • 程式運行發現錯誤,而且利用throw語句拋出一個checked異常
    • Java虛擬機器和執行階段程式庫出現的內部錯誤
  • 對於可能被他人使用的Java方法,更具異常規範(exception specification),在方法的首部聲明這種方法可能拋出異常,假設有多個用逗號隔開

    class MyAnimation{    ...    public Image loadImage(String s) throws IOException FileNotFoundException    {            ...    }}
  • 關於子類覆蓋超類的方法那一塊沒看懂

11.1.3 怎樣拋出異常
  1. 找到一個合適的異常類
  2. 在方法聲明
  3. 建立這個類的一個對象
  4. 將對象拋出

    String readData(Scanner in) thros EOFException{    ...    while(...)    {        if(!in.hasNext())        {            if(n<len)                throw new EOFException();        }    }    ...    return S;}//還能含有一個字串參數的構造器String girpe="Content-length " +len +",Recived" + n ;throw new EOFException(girpe);  
11.1.4 建立異常類
  • 建立一個派生於Exception的類 ,或者派生於Exception子類的類。

  • 一般須要定義兩個構造器,一個是預設的,另一個是帶有具體描寫敘述資訊的構造器(超類Throwable的toString方法將會列印這些具體資訊)

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

    能獲得Throwable對象具體描寫敘述資訊,即構造時丟進去的String。

11.2 捕獲異常
  • 假設異常沒有被捕獲,程式將會停止運行
  • 假設想捕獲異常,下面是最簡單的try/catch 語句塊

    try{    code    more code     more code}catch (ExceptionType e){    handler for this type }
  • 假設try語句塊中的不論什麼代碼拋出了在catch子句中說明的異常。那麼

    1. 跳過剩下的try 語句
    2. 將運行catch子句中的處理器代碼
  • 下面是個簡單的範例

    public void read(String filename){    try     {        InputStrem in = new FileInputStream(filename);        int b;        while((b!=in.read())!=-1)        {            process input;        }    }    catch (IOException exception)    {        exception.printStackTrace();    }}

對於以上代碼

通常最好的選擇是什麼都不做,而是將異常傳遞給調用者。

假設read方法出現了錯誤,就讓read方法的調用者去擔心!

假設採用這樣的處理方式,就必須聲明這種方法可能會拋出一個IOException

public void read(String filename) throws IOException{        InputStrem in = new FileInputStream(filename);        int b;        while((b!=in.read())!=-1)        {            process input;        }}
  • 不同意子類覆蓋超類的方法中throws說明符超過超類所列出的異常範圍。假設有不屬於的,不能throws掉,僅僅能自己捕獲處理
11.2.1 捕獲多個異常
  • 基本語句

    try {}catch (FileNotFoundException e){}catch (UnknownHostException e){}catch (IOException e){}
  • 假設須要獲得具體資訊

    e.getMessage() //具體錯誤資訊e.getClass().getName()  //異常對象的實際類型
  • 假設處理方式一樣 合并catch語句

    try{    code..}catch (FileNotFoundException | UnknownHostException e){}
11.2.2 再次拋出異常或異常鏈
  • 捕獲異常再次拋出的基本方法

    try{    access the database}catch (SQLException e){    throw new ServletException("database error: "+e.getMessage());}
  • 另一種能不丟失原始異常的方法

    try{    access the database}catch (SQLException e){    Throwable se=new ServletException("database error");    se.initCause(e);    throw se;}

    當捕獲異常時。能夠用下面語句又一次得到原始異常:

    Throwable e = se.getCause();

    書上強烈建議這樣的封裝方式,不丟失原異常的細節。

  • 有時僅僅是記錄異常

    try{    access the database}catch (SQLException e){    logger.log(level,message,e);    throw e;}
11.2.3 finaly子句
  • 基本的文法

    try{}catch(Exception e){}finally{        in.close();}
  • 不管try中拋出異常,還是catch中拋出異常,總而言之finall總會運行

  • 強烈使用try/catch 和 try/finally語句塊單獨,而不是基本的文法的使用方法。例如以下:

    InputStream in= ... ;try {    try     {        code that might throw exceptions    }    finally    {        in.close();    }}catch(IOException e){    show error message}

    內層的try僅僅有一個職責,確認關閉輸入資料流。外層的try 用來確保報告出現的錯誤。

  • 注意:當finallycatch包括return語句,會運行finallyreturn

  • 注意finally 也可能拋出異常,而導致本來要catch拋出的異常被覆蓋

11.2.4 帶資源的try語句
  • 假如資源實現了AutoCloseable/Closeable介面的類。能夠利用帶資源的try語句

    try(Resource res=...){    work with res}
  • try 退出時,會自己主動調用res.close()。下面給出一個典型的範例。

    try (Scanner in=new Scanner(new FileInputStream("/usr/share/dict/words"))){    while (in.hasNext())        System.out.println(in.next());}
  • 還能指定多個資源,比如:

    try (Scanner in = new Scanner(new FileInputStream("/usr/share/dict/words")),    PrintWriter out=new PrintWriter("out.txt")){    while(in.hasNext())        out.println(in.next().toUpperCase());}
  • 假設.close()也拋出了異常,可是不會覆蓋原來該拋出的異常,而是被抑制。假設你想知道這些被抑制的異常,能夠通過getSuppressed方法。

11.2.5 分析堆疊追蹤元素
  • 堆疊追蹤(stack trace)是一個方法調用過程的列表。

  • 比較靈活的方式是使用getStackTrace()

    它會得到StackTraceElement對象的一個數組。


    比如:

    Throwable t = new Throwable();StackTraceElement[] frames = t.getStackTrace();for(StackTraceElement f : frames)    System.out.println(f);  輸出factorial(4):StackTraceTest.factorial(StackTraceTest.java:8)StackTraceTest.factorial(StackTraceTest.java:14)StackTraceTest.factorial(StackTraceTest.java:14)StackTraceTest.factorial(StackTraceTest.java:14)StackTraceTest.factorial(StackTraceTest.java:14)StackTraceTest.factorial(StackTrcaceTest.java:14)StackTraceTest.main(StackTraceTest.java:23)

    能獲得檔案名稱,類名。當前啟動並執行程式碼號

  • 靜態Thread.getAllStackTrace方法,獲得全部線程的堆疊追蹤。下面是範例

    Map<Thread,StackTraceElement[]> map=Thread.getAllStackTraces();for(Thread t : map.keySet()){    StackTraceElement[] frames=map.get(t);        for(StackTraceElement f : frames)            System.out.println(f);}
11.3 使用異常機制的技巧
  • 異常不能取代簡單的測試
  • 不要過分細化異常
  • 利用異常階層
  • 不要羞於傳遞異常。有時候你是類設計者,應該由使用者決定對異常怎麼樣
11.4 使用斷言
  • assertkeyword有兩個表達形式

    assert 條件;//為false ,拋出一個AssertionError異常assert 條件:運算式;//運算式傳入異常作為一個訊息字串。
11.4.1 啟用或者禁用斷言
  • -ea或 -enableassertions啟用,預設是禁用
  • 也能啟動部分包的斷言,也能金庸部分包的斷言
11.4.2 使用斷言完畢參數檢查
  • 宣告失敗是致命的,不可恢複的錯誤。

  • 斷言檢查僅僅用於開發和測試階段。
  • 斷言是一種測試和調試階段所使用的戰術性工具,而日誌記錄是一種在程式的整個生命週期都能夠使用的策略工具。

11.5 記錄日誌11.5.1 基本日誌
  • 日誌系統管理著一個名為Logger.global的預設日誌記錄器,能夠用System.out替換它,並通過info方法記錄日誌資訊

    Logger.getGlobal().info("File->Open menu item selected");//print     //三月 15, 2016 7:33:25 下午 log main   //資訊: File->Open menu item selected

    自己主動包括了時間,調用的類名和方法。

  • Logger.gelGlobal().setLevel(Level.OFF)來取消全部日誌

11.5.2 進階日誌
  • 調用getLogger方法能夠建立或檢索記錄器

    Logger myLogger= Logger.getLogger("log.zhouyong");
  • 假設對日誌設定了記錄層級。那麼它的子記錄器也會繼承這個屬性

  • 有一下7個日誌記錄器層級

    • SEVERE
    • WARNING
    • INFO
    • CONFIG
    • FINE
    • FINER
    • FINEST

    在預設情況。僅僅記錄前三個層級。也能夠設定其它層級。比如:

    logger.setLevel(Level.FINE)

    如今,FINE和更進階別的記錄都能夠記錄下來

    另外能夠使用Level.ALL 開啟全部 Level.OFF 關閉全部

  • 有下面幾種記錄方式

    logger.warning(message);logger.fine(message);//同一時候還能夠用log方法指定層級logger.log(Level.FINE,message);
  • 一般用CONFIG,FINE等記錄有助於診斷,但對於程式猿沒有太大意義的調試資訊。

  • 預設的日誌記錄將顯示包括日誌調用類名和方法名。可是假設虛擬機器進行了最佳化,可能無法得到準確的資訊。此時須要logp方法獲得調用類和方法的確切位置,簽名例如以下:

    void logp(level l,String className,String methodName,String message)

    下面另一些跟蹤運行流的方法

    void entering(String className,String methodName)void entering(String className,String methodName,Object param)void entering(String className,String methodName,Object[] params)void exiting(String className,String methodName)void exiting(String className,String methodName,Object result)

    比如:

    不知道有什麼用。。

  • 記錄日誌的經常使用用途是記錄那些不可預料的異常。能夠使用一下兩種方式。

    void throwing(String className,String methodName,Throwable t)void log(Level l,String message ,Throwable t)

    典型的使用方法是:

    if(...){    IOExcption exception = new IOException("...");    logger.throwing("com.my","read",exception);    throw exception;    //FINER層級}

    還有

    try{    ...}catch (IOException e){    Logger.getLogger("...").log(Level.WARNING,"Reading image",e);}
11.5.3 改動日誌管理器配置
  • 預設情況,設定檔存在於:

    e/lib/logging.properties
  • 要想使用自己的設定檔 須要

    java -Djava.util.logging.config.file=configFile MainClass
  • 改動預設的日誌記錄層級

    .level=INFO

    還能改動自己日誌記錄層級
    com.mycompany.myapp.level=FINE

  • 控制台也有輸出層級限制

    java.util.logging.ConsoleHandler.level=FINE

  • 日誌屬性由java.util.logging.LogManager類處理。具體看API

11.5.4 本地化
  • 不太懂 以後瞭解
11.5.5 處理器
  • 日誌記錄器先會將記錄發送到父處理器中,終於的處理器有一個ConsoleHandle

  • 對於一個要被記錄的日誌記錄,它的日誌記錄層級必須高於日誌記錄器和處理器的閾值。

    要想記錄FINE層級的日誌。就必須改動設定檔裡的預設日誌記錄層級和處理器層級。
    另外,還能夠繞過設定檔,安裝自己的處理器。

    //控制台處理器

    Logger logger=Logger.getLogger("log.zhouyong");logger.setLevel(Level.FINE);logger.setUseParentHandlers(false);Handler handler = new ConsoleHandler();handler.setLevel(Level.FINE);logger.addHandler(handler);logger.log(Level.FINE,"dddd");

    在預設情況,日誌記錄器會將記錄發送給自己的處理器和父處理器。

    父處理器就是一般的預設處理器,可是既然我們有了自己的處理器,能夠把父處理器關了。免得控制台發送了兩次記錄

  • 要想將日誌發送到別的地方,就須要其它處理器。

    • FileHandler 收集檔案裡的日誌
    • SocketHandler。 發送到特定的主機和port
  • FileHandler

    FileHandler handler = new FileHandler();handler.setLevel(Level.FINE);logger.addHandler(handler);logger.log(Level.FINE,"dddd");

    檔案在User底下。格式為XML。例如以下:

    <?xml version="1.0" encoding="GBK" standalone="no"?

    ><!DOCTYPE log SYSTEM "logger.dtd"><log><record> <date>2016-03-15T23:40:17</date> <millis>1458056417956</millis> <sequence>0</sequence> <logger>log.zhouyong</logger> <level>FINE</level> <class>log</class> <method>main</method> <thread>1</thread> <message>dddd</message></record></log>

  • 還能有很多其它的複雜方式來處理完畢自己想要的要求
11.5.6 過濾器
  • 每一個記錄器和處理器都能夠有一個可選的過濾器來完畢附加的過濾
  • 能夠通過實現Filter介面並定義下列方法來自己定義過濾器

    boolean isLoggable(LogRecord record)
  • setFilter方法安裝過濾器

11.5.7 格式化器
  • ConsoleHandler類FileHandler能夠產生文本或 XML格式的日誌記錄。可是也能夠自己定義格式。

  • 通過繼承Formatter類,並覆蓋一下方法。

    String format(LogRecord record)
  • 能夠依據自己意願對記錄的資訊進行格式化,並返回結果字串。

  • 然後用setFormatter方法將格式化器安裝到處理器中。

11.5.8 日誌記錄說明

[core java學習筆記][第十一章異常斷言日誌調試]

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.