effectiveJava

Effective Java Item76 - 使失敗保持原子性

這篇是Effective Java - Strive for failure atomicity章節的讀書筆記 本篇的程式碼來自於原書內容

Item76: 使失敗保持原子性

在一個異常拋出之後 我們希望我們的物件還仍然維持在一個定義良好且可以被使用的狀態 即使你是在一個很長的方法的中途拋出異常也是一樣

這對於會拋出受檢異常的方法特別重要 因為我們希望你處理這個例外

處理的準則是我們希望能讓物件的狀態回復到呼叫這個方法之前 對於有達成這個要求的方法 我們稱之為具有失敗原子性 意思就是你要碼成功 如果失敗的話你就當作沒發生過 不能把我的東西弄壞

Alt text

情況一 物件不可變

最簡單達成目的的方式 就是讓你的物件不可變 既然不可變 那他就不可能變成一個不合理的狀態 當你需要一個新對象你就再創一個 讓Constructor幫你篩選掉不合理的新物件

簡單的例子就是String的substring方法

"unhappy".substring(2) // "happy"

“unhappy”這個物件不會被變動 所以substring就具有失敗原子性

情況二 物件可變

方法一: 在方法的開頭檢查參數

細節可以參考檢查參數的有效性: 這讓你可以在真正開始修改對象之前 就發現這個修改會拋出錯誤 不要真的去改了才發現 要三思而後行

方法二: 廣義的方法一 調整計算處理的順序 讓任何可能會失敗的計算部分都在狀態修改之前發生

方法三: 比較消極 就是編寫恢復代碼 讓你的物件原封不動回到呼叫這個方法前的狀態

方法四: 要做事情前 先把物件拷貝一份 在複製品上操作 操作錯了就算了 本尊沒事 如果做完成功了 那就讓複製品取代本尊

Alt text

例外

對於失敗原子性的要求 在多線程的方法中如果沒有適當的同步機制 幾乎是沒有辦法達成

總結

作為方法規範的一部分 任何異常都應該要能回復你傳入物件的狀態 以保持失敗原子性 如果你的方法沒有維持這個原則 你就應該清楚的寫在你的文件裡 包括傳入的物件會變成什麼狀態 可惜的是當今大多數的文件都沒做到這點