理解錯誤才能錯得不糊塗、錯得到位、錯得妙!
如何看出工程師的底子瞧瞧他 Debug 的姿勢準沒錯,優秀工程師們往往能夠正確地找到問題點、用精確的關鍵字找到最佳解,除了依靠經驗的累積外,更重要的是面對錯誤是否都能掌握問題原因,甚至是了解如何防範以及類似做法有哪些?身為一名 Android 工程師,今天來聊聊 Java 中的 Checked 以及 Unchecked Exception!
Checked Exception
Checked Exception
和 Unchecked Exception
都是繼承自 Exception
,而 Exception
則是繼承自 Throwable
, Checked Exception
是在編譯階段 ( compile time ) 就會發現的錯誤,因為是已知的錯誤所以一定要對 Checked Exception
進行錯誤處理 ( Exception Handling ),例如用 try { } catch(e: Exception) { }
處理錯誤發生的情況,或是讓錯誤的 function 回傳 java.io.IOException
。常見的 Checked Exception
像是讀取或寫入檔案時找不到檔案的 Exception ( FileNotFoundException ),或是找不到某個類別 ( ClassNotFoundException )。
Unchecked Exception
Unchecked Exception
與 Checked Exception
相反,是編譯時期不會發現,到 Runtime 時才會發現的錯誤,也稱為 Runtime Exception
。由於編譯器也檢查不到錯誤在哪里,因此也不會要求預先進行錯誤處理,只有到運行到該部分邏輯時才會報錯。常見的 Unchecked Exception
像是指定型別錯誤 ( ClassCastException ),空指針錯誤 ( NullPointerException,又稱 NPE )。雖然編譯器沒有要求處理 Unchecked Exception,但我們還是可以預先進行錯誤處理,例如給予預設值,或是先確認非空值再繼續操作,或是提示錯誤訊息提醒用戶,都可以預防未經處理的 Unchecked Exception 直接噴 throwable 導致 JVM 強制終止程序的崩潰。
在 Kotlin 中新增了 lateinit 可以預先定義非空值的變數,直到需要時才實作。但若在實作前就先行調用,則會拋出 UninitializedPropertyAccessException
,提醒開發者該變數尚未實作,相當於在 Java 的 Setter 中加上以下的判斷:
if (value == null)
throw new UninitializedPropertyAccessException("Property has not been initialized");
由於 lateinit 的錯誤也是 runtime 時才會發現,因此也屬於 Unchecke Exception。
有意義的錯誤
為了避免錯誤造成程序終止,開發者往往會佈下天羅地網要避免 Unchecked Exception
,也有一派主張 Defensive Programming 的開發目標,無論如何都要讓程序保持持續運作,但過度的錯誤處理以避免 Exception 的發生,反而可能造成找不到錯誤進而陷入難以維護的窘境。
在應該錯誤的地方就應該報錯,對於開發者來說才是合理且可維護的程式碼。當 Exception 發生時會產生 throwable,透過throwable.printStackTrace()
可以還原錯誤發生的情況並有助於定位問題。
剛開始開發時看到 compiler 的 Logcat 上一堆紅色提示就覺得壓力山大,但害怕是因為不了解,而了解錯誤的類型是定位錯誤的第一步,後來漸漸發現原來 stacktrace 或 Log 上都藏著一堆寶貝呢!最後以主管的話和大家共勉之:)
不怕錯誤,修掉就好,怕的是 regression 的錯誤,以為修好了卻一錯再錯 (怕