《Java核心技術》閱讀筆記(三)- 異常處理

JavaCoreNote–異常

如果由於出現錯誤而使得某些操作沒有完成,程序應該:
• 返回到一種安全狀態,並能夠讓用戶執行一些其他的命令;或者
• 允許用戶保存所有操作的結果,並以妥善的方式終止程序

異常

for:將控制權從錯誤產生的地方轉移給能夠處理這種情況的錯誤處理器

程序錯誤分類:

  1. 用戶輸入
  2. 物理限制
  3. 設備
  4. 代碼
    處理方式:返回一個特殊的錯誤碼;不返回任何值,而是拋出一個封裝了異常信息的對象,尋找對應的錯誤處理器。

語法

分類
  • 非受查異常(unchecked)
    Error、RuntimeException
    Error類層次結構描述了 Java 運行時系統的內部錯誤和資源耗盡錯誤;
    RuntimeException:程序錯誤導致的異常,包括情況:

    • 錯誤的類型轉換
    • 數組訪問越界
    • 訪問null指針
      如果出現RuntimeException異常,一定是程序員的問題
  • 受查異常(checked)
    非RuntimeException表示程序本身沒有問題,但由於像IO錯誤這類的異常

何時聲明
  1. 調用一個拋出受査異常的方法
  2. 程序運行過程中發現錯誤,並且利用throw語句拋出一個受查異常
  3. 程序出現錯誤拋出非受查異常
  4. 虛擬機和運行時庫出現的內部錯誤

注:不應聲明從Error繼承來的錯誤、從RuntimeException繼承來的異常

一個方法必須聲明所有可能拋出的受查異常,而非受查異常要麼不可控制(Error),要麼就應該避免發生(RuntimeException)

拋出異常
  1. 找到合適異常類
  2. 創建異常類對象
  3. 將對象拋出

定義異常類:派生於Exception或其子類的類,提供兩個構造器
注:不允許子類的throws說明符中出現超過超類方法所列出的異常類範圍

捕獲異常
  • try/catch語句塊
  • 何時捕獲,何時拋出?——捕獲哪些知道如何處理的異常
  • 捕獲多個異常時,異常變量隱含爲final變量
  • catch語句中可再次拋出異常,爲了轉換異常的類型,可設置異常原因initCause,getCause可重新獲得
finally子句

for:資源回收問題,如果沒有finally子句,一樣的代碼將在兩個地方出現。
finally子句中包含return語句將覆蓋try中的return

解耦合try/catch和try/finally語句塊,內層負責關閉資源,外層負責確保報告出現的異常

InputStrean in = . . .;
try
{
    try
    {
        code that might throwexceptions
    }
    finally
    {
        in.cose(); 
    } 
}
catch (IOException e) {
    show error message
}

finally子句可能產生異常,覆蓋原始的異常信息。

帶資源的try語句
  • 資源屬於實現AutoClosable接口的類,會自動調用close方法。
  • 帶資源的try語句也可以有自己的catch、finally子句,這些子句會在調用了關閉資源之後執行。實際中,避免加入過多內容,很少這樣使用這種情況。
    對於finally子句產生異常覆蓋原始異常的問題,會自動調用addSuppressd方法添加到原始異常的抑制異常中,拋出原始異常,處理器可調用getSuppressed獲得異常列表。
堆棧軌跡
  • Throwable.printStackTrace、getStackTrace
  • Thread.getAllStackTrace

使用技巧

  1. 異常處理不能代替簡單測試
  2. 不要過分細化異常,使代碼膨脹
  3. 利用異常層次結構
  4. 不要壓制異常
  5. 檢測錯誤時,苛刻比放任更好(早拋出)
  6. 不要羞於傳遞異常(晚捕獲)

斷言

for:有選擇的啓用檢測

斷言機制允許在測試期間向代碼中插入一些檢査語句。當代碼發佈時,這些插人的檢測語句將會被自動地移走

使用

  1. assert 條件;
    assert 條件:表達式;
    條件不成立時拋出AssertionError異常,第二種形式中表達式生成一個說明字符串。

  2. 啓用禁用
    不需要重新編譯,是類加載器的功能。
    啓用:-enableassertions 或 -ea
    可在某個類或包中啓用:
    java -ea:MyClass -ea:com.mycompany.mylib… MyApp
    禁用:-disableassertions 或 -da

對於系統類(沒有類加載器),使用:enablesystemassertions/-esa
程序中也可以控制,參看API

  1. 何時使用
  • 斷言失敗是致命的、不可恢復的錯誤;
  • 斷言檢查只用於開發和測階段

日誌

日誌API優勢:

  1. 很容易開啓、取消全部或某個級別日誌記錄;
  2. 可以被定向到不同處理器;
  3. 記錄器和處理器可以對記錄過濾;
  4. 不同方式格式化;
  5. 可以用多個日誌記錄器;
  6. 默認用配置文件控制,也可用程序替換配置。

基本日誌

  1. 調用全局記錄器(global logger)
  2. 取消:Logger.getGlobal().setLevel(Off)

高級日誌

  1. 記錄器具有層次結構,子繼承父的屬性
  2. 7個級別:SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST,默認前三個

默認記錄類名、方法名信息,但VM可能進行優化得不到準確調用信息,可使用logp方法獲得調用類和方法的確切信息

作用:

  1. 用來跟蹤執行流的方法:entring、exiting
  2. 記錄不可預料的異常:throwing、log

修改日誌管理器配置

默認:jre/lib/1ogging.properties
修改:java -Djava.util.logging.config.file=configFile MainClass

修改日誌級別 名稱.level=FINE
默認日誌管理器:java.util.logging.LogManager
可通過系統屬性修改:java.util.logging.manager

處理器

  • 默認使用ConsoleHandler
  • 默認INFO級java.uti1.1ogging.ConsoleHandler.level
  • 默認發送到處理器及父處理器

其他處理器:FileHandler、SocketHandler
可修改文件處理器的默認行爲

過濾器

實現Filter,記錄器或處理器中setFilter方法使用

格式化

實現Formatter,處理器中setFormatter方法使用

常用操作

  1. 日誌記錄器命名爲主程序包名
  2. 程序中安裝默認配置
  3. 只將對用戶有用的日誌設置爲前3個級別,顯示在控制檯。

調試技巧

  1. 打印變量;
  2. 在類中放置main方法,對每個類做單元測試;
  3. 使用JUnit組織測試用例
  4. 使用日誌代理(logging proxy)截獲方法調用,記錄日誌
  5. 打印堆棧軌跡Thread.dumpStack()
  6. 捕獲堆棧軌跡到字符串
  7. 捕獲錯誤信息到文件java MyProgram 2> errors.txt
    java MyProgram 1> errors.txt 2>&1
  8. 非捕獲異常的堆棧軌跡保存到文件中,可以調用靜態的 Thread.setDefaultUncaughtExceptionHandler方法改變非捕獲異常的處理器
  9. 觀察類的加載過程,可以用-verbose標誌啓動Java虛擬機
  10. -Xlint選項告訴編譯器對一些普遍容易出現的代碼問題進行檢査
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Vg4mJ7vS-1582984683851)(evernotecid://1520493E-927F-420A-8EE1-BA6F74088A9D/appyinxiangcom/11767354/ENResource/p3065)]
  11. 利用JVM對Java應用程序進行監控(monitoring)和管理 (management)的支持
    jconsole processID
  12. jmap實用工具獲得一個堆的轉儲
    jmap -dump:format=b,file=dumpFileName processID
    jhat dumpFileName
    進人localhost:7000
  13. 使用 -Xprof 標誌運行 Java 虛擬機, 就會運行一個基本的剖析器來跟蹤那些代
    碼中經常被調用的方法

小結

本文整理了程序錯誤的分類,除了返回特殊的返回值外,Java語言中可通過拋出異常對象、捕獲異常的方式處理程序中出現的問題。通過不同日誌級別記錄程序運行中的業務、程序信息,通過斷言實現程序開發、測試階段的程序檢測。

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