一 .兩種異常結(jié)構(gòu)
java中的異常和錯誤都繼承自java.lang.Throwable
在異常處理的時候,都會接觸到受檢異常(checked exception)和非受檢異常(unchecked exception)這兩種異常類型。
非受檢異常指的是java.lang.RuntimeException和java.lang.Error類及其子類,所有其他的異常類都稱為受檢異常。兩種類型的異常在作用上并沒有差別。
兩者的區(qū)別主要在:受檢的異常是由編譯器強(qiáng)制執(zhí)行的,必須捕獲,用于指示不受程序控制的異常情況(例如,I/O 錯誤),而非受檢的異常在運(yùn)行時發(fā)生,用于指示編程錯誤(例如,空指針。正因為如此,受檢異常在使用的時候需要比非受檢異常更多的代碼來避免編譯錯誤。
二 .兩者的常見異常
| uncheckedExcepiton(RuntimeException) | CheckedException |
|---|---|
| Java.lang.ArithmeticException Java.lang.ArrayStoreExcetpion Java.lang.ClassCastException Java.lang.EnumConstantNotPresentException Java.lang.IllegalArgumentException Java.lang.IllegalThreadStateException Java.lang.NumberFormatException Java.lang.IllegalMonitorStateException Java.lang.IllegalStateException Java.lang.IndexOutOfBoundsException Java.lang.ArrayIndexOutOfBoundsException Java.lang.StringIndexOutOfBoundsException Java.lang.NegativeArraySizeException’ Java.lang.NullPointerException Java.lang.SecurityException Java.lang.TypeNotPresentException Java.lang.UnsupprotedOperationException | Java.lang.ClassNotFoundException Java.lang.CloneNotSupportedException Java.lang.IllegalAccessException Java.lang.InterruptedException Java.lang.NoSuchFieldException Java.lang.NoSuchMetodException |
非受檢異常
RuntimeException在默認(rèn)情況下會得到自動處理。所以通常用不著捕獲RuntimeException,但在自己的封裝里,也許仍然要選擇拋出一部分RuntimeException。
RuntimeException是那些可能在 Java 虛擬機(jī)正常運(yùn)行期間拋出的異常的超類??赡茉趫?zhí)行方法期間拋出但未被捕獲的RuntimeException的任何子類都無需在throws子句中進(jìn)行聲明。(java api)-
受檢異常,是值需要顯示通過
Catch捕獲的異常,在Java中,除了RuntimeException以外的異常,都屬于受檢異常(checkedException).
我們以NoSuchMethodException為例,如圖所示,可以明顯看到,該異常在沒有捕獲的情況下,會顯示提示語法錯誤,有兩個解決辦法-
Add exception to method signature,表示把這個異常再往上拋。 -
Surround with try/catch,表示使用try/catch捕獲。
img
-
三 異常的選擇
一直以來,關(guān)于在程序中到底是該使用受檢異常還是非受檢
我們通常需要保證程序不會捕捉到不在我們預(yù)期范圍內(nèi)的異常,比如RuntimeException,我們希望這類異常是要往外拋,而不是在內(nèi)部被捕獲。不要讓它把異常吞掉,因為一旦程序出現(xiàn)問題,沒有異常信息很難定位。
如果希望調(diào)用者能夠從異常中進(jìn)行合理恢復(fù),需要設(shè)置為受檢異常類型,如果調(diào)用者無法采用任何措施使得程序無法重異常中恢復(fù),需要把該異常設(shè)置為非受檢異常。
四. 擴(kuò)展:一道經(jīng)典的面試題
一道非常經(jīng)典的面試題,NoClassDefFoundError 和 ClassNotFoundException 有什么區(qū)別?
-
NoClassDefFoundError,表示這個類在編譯時期存在,但是在運(yùn)行時不能找到合適的類導(dǎo)致的錯誤。例如在運(yùn)行時我們想調(diào)用某個類的方法或者訪問這個類的靜態(tài)成員的時候,發(fā)現(xiàn)這個類不可用,此時Java虛擬機(jī)就會拋出NoClassDefFoundError錯誤。
可能出現(xiàn)的錯誤情況如下:
對應(yīng)的Class在java的classpath中不可用
你可能用jar命令運(yùn)行你的程序,但類并沒有在jar文件的manifest文件中的classpath屬性中定義
可能程序的啟動腳本覆蓋了原來的classpath環(huán)境變量
因為NoClassDefFoundError是java.lang.LinkageError的一個子類,所以可能由于程序依賴的原生的類庫不可用而導(dǎo)致
檢查日志文件中是否有java.lang.ExceptionInInitializerError這樣的錯誤,NoClassDefFoundError有可能是由于靜態(tài)初始化失敗導(dǎo)致的
如果你工作在J2EE的環(huán)境,有多個不同的類加載器,也可能導(dǎo)致NoClassDefFoundError
- ClassNotFoundException,它是程序運(yùn)行期間的異常,比如當(dāng)我們嘗試在運(yùn)行時使用反射加載類時,ClassNotFoundException 就會出現(xiàn)。
@CallerSensitivepublic static Class<?> forName(String className) throws ClassNotFoundException
{
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
總的來說,ClassNotFoundException 和 NoClassDefFoundError 都是由 CLASSPATH中缺少類引起的,通常是由于缺少 JAR 文件而引起的,但是如果 JVM 認(rèn)為應(yīng)用運(yùn)行時找不到相應(yīng)的引用,就會拋出 NoClassDefFoundError 錯誤;當(dāng)你在代碼中顯示的加載類比如 Class.forName() 調(diào)用時卻沒有找到相應(yīng)的類,就會拋出java.lang.ClassNotFoundException。
問題解答
面試題:請你說一下對受檢異常和非受檢異常的理解·
回答: 受檢異常和非受檢異常,都是派生自Throwable這個類。他們的區(qū)別是
受檢異常: 是指需要調(diào)用者顯示通過try-catch捕獲的異常
非受檢異常: 是指不需要調(diào)用者顯示捕獲的異常。
之所以要定義受檢異常和非受檢異常主要是因為兩者有著不同的作用
在程序中,存在一些需要用戶在編譯期間就去檢查的問題,比如FileNotFoundException、IOException,這些異常涉及資源處理,調(diào)用者需要捕獲,其實(shí)它可以提醒開發(fā)者,如果被調(diào)用的方法出現(xiàn)這類異常時,程序應(yīng)該做好預(yù)判并處理,比如IOExcetion,我們需要對流進(jìn)行關(guān)閉操作。
而非受檢發(fā)生在運(yùn)行期間,是程序運(yùn)行過程中可能發(fā)生的錯誤類型,比如NullpointExcetpion,這些異常我們可以捕獲,也可以不捕獲。但是捕獲這些異常只能打印一些日志,除此之外什么都做不了
