Checked vs UnChecked 異常 ,使用場合?
異常的概念
任何的異常都是Throwable類(為何不是接口??),并且在它之下包含兩個字類Error / Exception,而Error僅在當在java虛擬機中發生動態連接失敗或其它的定位失敗的時候,Java虛擬機拋出一個Error對象。典型的簡易程序不捕捉或拋出Errors對象,你可能永遠不會碰到需要實例化Error的應用,那就讓我們關心一下Exception。
Exception中比較重要的就是RuntimeException(運行時異常)-可能在執行方法期間拋出但未被捕捉的 RuntimeException 的任何子類都無需在 throws 子句中進行聲明,也就是說你的應用應該不去“關心”(說不關心是不服責任的,但只是你不應該試圖實例化它的字類)。 RuntimeException,就如同你不應該關心Error的產生與處理一樣!RuntimeException描述的是程序的錯誤引起來的,因該由程序負擔這個責任?。?u>從責任這個角度看Error屬于JVM需要負擔的責任;RuntimeException是程序應該負擔的責任;checked exception 是具體應用負擔的責任)
除了Error與RuntimeException,其他剩下的異常都是你需要關心的,而這些異常類統稱為Checked Exception,至于Error與RuntimeException則被統稱為Unchecked Exception.
關于 Java 中引入的 Checked Exceptions,目前存在著很多反對意見。正方的觀點是引入 Checked Exceptions,可以增加程度的魯棒性。反方的觀點是 Checked Exceptions 很少被開發人員正確使用過,并且降低了程序開發的生產率和代碼的執行效率。
Java 中定義了兩類異常:
1) Checked exception: 這類異常都是Exception的子類 。異常的向上拋出機制進行處理,假如子類可能產生A異常,那么在父類中也必須throws A異常??赡軐е碌膯栴}:代碼效率低,耦合度過高。C#中就沒有使用這種異常機制。
2) Unchecked exception: 這類異常都是RuntimeException的子類,雖然RuntimeException同樣也是Exception的子類,但是它們是非凡的,它們不能通過client code來試圖解決,所以稱為Unchecked exception 。
(JAVA視線論壇robbin's view,個人覺得用來做業務流程控制違反了Exception設計的初衷,但可以借鑒一下)
在使用UseCase來描述一個場景的時候,有一個主事件流和n個異常流。異常流可能發生在主事件流的過程,而try語句里面實現的是主事件流,而catch里面實現的是異常流,在這里Exception不代表程序出現了異?;蛘咤e誤,Exception只是面向對象化的業務邏輯控制方法。假如沒有明白這一點,那么我認為并沒有真正明白應該怎么使用Java來正確的編程。
而我自己寫的程序,會自定義大量的Exception類,所有這些Exception類都不意味著程序出現了異?;蛘咤e誤,只是代表非主事件流的發生的,用來進行那些分支流程的流程控制的。例如你往權限系統中增加一個用戶,應該定義1個異常類,UserExistedException,拋出這個異常不代表你插入動作失敗,只說明你碰到一個分支流程,留待后面的catch中來處理這個分支流程。傳統的程序員會寫一個if else來處理,而一個合格的OOP程序員應該有意識的使用try catch 方式來區分主事件流和n個分支流程的處理,通過try catch,而不是if else來從代碼上把不同的事件流隔離開來進行分別的代碼撰寫。
(另外一種觀點,不同于robbin,個人贊同,并引用于此)
1。什么時候拋出異常--涉及到服務類
2。拋出checked還是unchecked的異常--涉及到客戶類
對第一個問題來說,我想異常本身這個字解釋了某些東西,異常就是我們認為在正常情況下不可能發生的問題,并且服務代碼不知道如何去處理。譬如說我做一個監控程序,需要用壓縮卡提供的API去初始化所有的板卡,API提供的是boolean型的返回值,但我把這個API變成拋出一個異常,因為除非非凡原因,我不認為會發生初始化失敗的情況,當然更不知道怎樣去處理這個問題。又譬如Hibernate里面的LoadObject使用沒有發現這個對象存在,那Hibernate也是認為不可能的,除非其他代碼直接刪除了數據庫里面的記錄,那么也需要拋出異常。當然Hibernate本身也不知道如何處理這種情況。
但是假如發生的情況是可以預期的,那我不認為應該拋出例外。象上面這個userExist的情況,我認為應該在前面已經分流,應該首先判定這個用戶是否存在,if(userExists()),然后進行處理,而不應當拋出例外。以及login應當返回true或者false。也就是說,這些屬于程序的正常流程,而不是例外,不是異常。把例外作為正常程序流程的控制機制,只不過是把服務代碼中的if轉移到客戶代碼去,沒有減少任何需要處理的代碼,反而增加了系統的負擔(生成例外棧)。
還有拋出異常的情況是違反方法的先決條件,每一個方法都有自己的先決條件和后置條件,方法只有在正確的前提下才能執行達到一個正確的后果,(所謂類的不變量)。譬如你去存取一個數組的某一個元素,這個存取方法有一個前提條件,就是你的索引應當落入它的最大下標和最小下標之間,不然就應當拋出一個例外。
對于第二個問題,端視于客戶代碼是否能夠根據這個例外進行合理的處理。假如客戶代碼根本就不知道如何處理這個例外,應當把它作為一個unchecked例外,例如上面下標的問題,客戶代碼用一個不合法的下標來存取數組,那么拋出一個checked例外以后,客戶代碼是+1還是-1?顯然根本就不可能做出“合理的”處理,客戶既然不能處理,還要強制它去處理,那么就是捕捉,打印了事,沒有增加任何價值。但是假如是客戶可以處理的,或者可以選擇不同的方式處理的,那么就可能需要用checked,但我發現很少有這樣的情況。對于類似于RemoteException或者SQLException這些Exception,我一般都轉換為具體的業務Exception,而我所有的業務Exception都是RuntimeException.
所以我的觀點是,是否拋出例外就是服務代碼是否進行合理的處理,拋出什么類型的例外就是客戶代碼是否能夠合理的處理。
新聞熱點
疑難解答