天天看點

代碼整潔之道-第7章-錯誤處理-讀書筆記

第 7 章 錯誤處理

  錯誤處理很重要,但如果它搞亂了代碼邏輯,就是錯誤的做法。

7.1 使用異常而非傳回碼

  傳回錯誤碼,會搞亂調用者的代碼。調用者必須在調用之後即可檢查錯誤。遇到錯誤時,最好抛出一個異常。調用代碼很整潔,其邏輯不會被錯誤處理搞亂。

7.2 先寫 Try-Catch-Finally 語句

  異常的妙處之一是,它們在程式中定義了一個範圍。執行 try-catch-finally 語句中 try 部分的代碼時,你是在表明可随時取消執行,并在 catch 語句中接續。

  在某種意義上,try 代碼塊就像是事務。 catch 代碼塊将程式維持在一種持續狀态,無論 try 代碼塊中發生了什麼均如此。是以,在編寫可能抛出異常的代碼時,最好先寫出 try-catch-finally 語句。這能幫你定義代碼的使用者應該期待什麼,無論 try 代碼塊中執行的代碼出什麼錯都一樣。

  嘗試編寫強行抛出異常的測試,再往處理器中添加行為,使之滿足測試要求。結果就是你要先構造 try 代碼塊的事務範圍,而且也會幫助你維護好該範圍的事務特征。

7.3 使用不可控異常

  在 java 中可以捕獲的異常(Exception 類的子類)分為可控式異常和運作時異常量兩種類型。

  可控式異常:在 java 中把那些可以預知的錯誤,例如從檔案中讀取資料,對資料庫進行操作等,在程式編譯時就能對程式中可能存在的錯誤進行處理,并給出具體的錯誤資訊,我們把這些錯誤稱為可控式異常。例如,IOException、SQLException、ClassNotFoundException、NoSuchFieldException 等等。

  運作時異常:在 java 中有些錯誤是不能被編譯器檢測到的,例如,在進行觸發運算時,除數為零;試圖把一個不是由數字組成的字元串使用 Integer 的 parseInt() 方法轉換為整數等 java 的編譯器是檢測不到的,因而能正常編譯,但是在運作時就會發生異常,我們把這些異常稱為運作時異常。例如:IndexOutOfBoundsException、NullPointerException。

  可控異常的代價就是違反了開放/閉合原則。如果你在方法中抛出可控異常,而 catch 語句在三個層級之上,你就得在 catch 語句和抛出異常處之間的每個方法簽名中聲明該異常。這意味着對軟體中較低層級的修改,都将波及較高層級的簽名。修改好的子產品必須重新建構、釋出,即便它們自身所關注的任何東西都沒改動過。

  如果你在編寫一套關鍵代碼庫,則可控異常有時也會有用,你必須捕獲異常。但對于一般的應用開發,其依賴成本要高于收益。

7.4 給出異常發生的環境說明

  你抛出的每個異常,都應當提供足夠的環境說明,以便判斷錯誤的來源和處所。在 java 中,你可以從任何異常裡得到堆棧蹤迹(stack trace);然而,堆棧蹤迹卻無法告訴你該失敗操作的初衷。

  應建立資訊充分的錯誤資訊,并和異常一起傳遞出去。在消息中,包括失敗的操作和失敗類型。如果你的應用程式有日志系統,傳遞足夠的資訊給 catch 塊,并記錄下來。

7.5 依調用者需要定義異常類

  将第三方 API 打包是個良好的實踐手段。當你打包一個第三方 API ,你就降低了對它的依賴:未來你可以不太痛苦地改用其他代碼庫。在你測試自己的代碼時,打包也有助于模拟第三方調用。

  打包的好處還在于你不必綁死在某個特定廠商的 API 設計上。你可以定義自己感覺舒服的 API。而且能夠寫出更整潔的代碼。

  對于代碼的某個特定區域,單一異常類通常可行。伴随異常發送出來的資訊能夠區分不用錯誤。如果你想要捕獲某個異常,并且放過其他異常,就使用不同的異常類。

7.6 定義正常流程

  特例模式(SPECIAL CASE PATTERN):建立一個類或配置一個對象,用來處理特例。客戶代碼就不用應付異常行為了。異常行為被封裝到特例對象中。

7.7 别傳回 null值

  傳回 null 值容易引發錯誤。

  如果打算在方法中傳回 null 值,不如抛出異常,或是傳回特例對象。如果在調用某個第三方 API 中可能傳回 null 值的方法,可以考慮用新方法打包這個方法,在新方法中抛出異常或傳回特例對象。

  Java 有 Collections.emptyList() 方法,改方法傳回一個預定義不可變清單,可用于生成空清單(特例對象)。這樣編碼,就能盡量避免 NullPointerException 的出現,代碼也就更整潔了。

7.8 别傳遞 null 值

  在方法中傳回 null 值是糟糕的做法,但将 null 值傳遞給其他方法就更糟糕了。除非 API 要求你向它傳遞 null 值,否則就要盡可能避免傳遞 null 值。

  在大多數程式設計語言中,沒有良好的方法能對付由調用者意外傳入的 null 值。事已如此,恰當的做法就是禁止傳入 null 值。這樣,你在編碼的時候,就會時時記住參數清單中的 null 值意味着出問題了,進而大量避免這種無心之失。

7.9 小結

  整潔代碼是可讀的,但也要強固。可讀與強固并不沖突。如果将錯誤處理隔離看待,獨立于主要邏輯之外,就能寫出強固而整潔的代碼。做到這一步,我們就能單獨處理它,也極大地提升了代碼的可維護性。

7.10 文獻