
(上圖是圣卡塔利娜島,美國南加州的一個小島,也是 mac OS 10.15 版本的官方默認壁紙)
概述
Hello,大家好,我們又來講面試中的基礎題了,今天這是一道很經典又很猥瑣的題
說猥瑣是因為這兩個例外名字比較近似,但事實上他們完全不同,導致很多同學會經常容易把它們搞混
說經典是因為由這道題可以引出的問題有很多,例如:
- 考察候選人對 Java 例外體系的熟悉程度
- 考察候選人對例外體系分類的了解(Error / Exception)
- 深入考察對 Exception 的不同型別的理解
- 通過考察面試者如何處理例外,從而考驗面試者的編程功底
似乎有太多問題可以探討,先不展開了,本文主要講述區別然后會再擴展一下知識點,文章大綱如下:
- NoClassDefFoundError 和 ClassNotFoundException 區別的常見回答
- 那么 Error 和 Exception 有什么的區別 ?
- Exception 的例外型別有哪些?
- 使用例外有哪些注意事項?
NoClassDefFoundError 和 ClassNotFoundException 區別的常見回答
NoClassDefFoundError 是一種 Error,Error 在大多數情況下代表無法從程式中恢復的致命錯誤,產生的原因在于 JVM 或者 ClassLoader 在運行時類加載器在 classpath 下找不到需要的類定義(編譯期是可以正常找到的,所以和 ClassNotFoundException 不同的是這是一個運行期的 Error),這個時候虛擬機就會拋出 NoClassDefFoundError,通常造成該 ERROR 的原因是打包程序中漏掉了部分類,或者 jar 包出現損壞或篡改,對應的 Class 在 classpath 中不可用等等原因
ClassNotFoundException 是屬于 Exception 的運行時例外,大多是可以從代碼中恢復的例外型別,導致該例外的原因大多是因為使用 Class.forName() 方法動態的加載類資訊,但是這個類在類路徑中并沒有被找到,那么就會在運行時拋出 ClassNotFoundException
以上是大致的 NoClassDefFoundError 和 ClassNotFoundException 的區別,那么延伸一下可以探討 Java 型別體系中的 Error 和 Exception
Error 和 Exception 的區別
Error 和 Exception 都是繼承 Throwable 類,它們體現 Java 設計者在對例外的不同情況所進行的分類處理,在 Java 中只有 Throwable 類的實體才能被 try/catch 捕獲或者宣告拋出,
Error 在大多數情況下代表程式出現了致命并且不可恢復的錯誤,它們大多都是不可預測的錯誤,不需要也不能捕獲和拋出,例如常見的 OutOfMemeryError,StackOverFlowError,還有本文提到的 NoClassDefFoundError,他們都是 Error 的子類
Exception 屬于程式錯誤,大多是人為編碼所導致的,它們大多都可以預測,也可以通程序式處理讓程式正常流程,所以是需要進行捕獲(try/catch)或者宣告拋出(throw)的,Exception 還分兩種情況,可檢查例外 checked exception(編譯期例外),非檢查例外 unchecked exception(運行期例外)
可檢查例外是編譯期必須要顯示處理的例外,編譯器會強制要求處理這種的例外,不然編譯就不會通過,非檢查例外是程式在運行時出現的例外,大多是程式員處理不到導致的程式問題,例如常見的 NullPointerException,ArrayIndexOutOfBoundsException,本文標題的 ClassNotFoundException 就是屬于編譯期例外,在使用 Class.forName 需要強制處理
一圖勝千言,為了方便大家直觀感受,我大概畫了一個簡單的例外體系結構圖,僅供參考:

使用例外的注意事項
平時在操作例外的時候有什么需要注意的嗎?我們先看一段簡單的代碼示例
try {
// 業務代碼
// something happened
Thread.sleep(100);
} catch (Exception e) {
}
// 業務代碼
以上代碼犯了哪幾個明顯的錯誤?我簡單列舉一下:
- 捕獲例外應該使用特定的型別的 Exception
- 沒有對例外進行任何處理
為什么要捕獲特定型別的例外 ?主要有以下幾點
因為你的代碼會被團隊很多人閱讀,寬泛的使用 Exception 對所有例外進行處理會讓別人不好理解你代碼的例外,程式的主要目的也是要體現它的語意,例如 Thread.sleep 是明確拋出 InterruptedException,Class.forName 明確拋出 ClassNotFoundException,那么應該針對 InterruptedException,ClassNotFoundException 這種明確的例外進行明確的處理,而不是泛泛的使用 Exception 包住所有的例外
沒有對例外進行任何處理
這個問題其實比上面更嚴重,這種行為本質上是在掩蓋問題,不僅會導致出現各種詭異的問題,而且完全沒有線索可以跟蹤,沒有人可以猜測到程式是在哪里出了問題,導致定位問題非常低效,所以如果沒有拋出例外,最起碼也要把對應的的錯誤資訊 到日志內,而不是“生吞”例外,人為的為診斷設定障礙
總結
我們通過一個簡單的 NoClassDefFoundError 和 ClassNotFoundException 區別 的問題和一個簡單的例外處理程式 demo 牽引出 Java 的例外體系和不同的分類和平時對例外處理的注意事項
另外推薦大家在實踐中盡量使用統一例外處理的機制,例如 Spring 提供了幾種的全域例外處理機制:
- 實作 HandlerExceptionResolver 介面
- 在Controller內部,用 @ExceptionHandler 注解處理例外
- 全域 Controller 例外處理注解 @ControllerAdvice ,可以根據型別處理特定例外
今天文章寫到這里,希望可以幫助大家加深對例外概念的理解,碼字不易,覺得不錯可以點贊,轉發,你的鼓勵是我的動力
更多技術咨詢,請關注公眾號,find me !

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/42046.html
標籤:架構設計
上一篇:[七年技術總結系列][理論篇]-RBAC權限模型由淺入深
下一篇:23.網市場云建站系統部署
