我不明白在代碼中出現鏈式異常的優點。鏈式異常的優勢是什麼
考慮到ResourceLoader example from java world,如果程序員知道遇到ResourceLoadException
的可能性,爲什麼不捕獲相同的異常而不是SQLException
?否則,程序員可以在同一代碼中捕獲兩個例外情況,而不必拋出一個新的Throwable
實例?
我不明白在代碼中出現鏈式異常的優點。鏈式異常的優勢是什麼
考慮到ResourceLoader example from java world,如果程序員知道遇到ResourceLoadException
的可能性,爲什麼不捕獲相同的異常而不是SQLException
?否則,程序員可以在同一代碼中捕獲兩個例外情況,而不必拋出一個新的Throwable
實例?
任何人都可以提供需要鏈式異常的信息嗎?
文章說,這非常好:
異常鏈可以讓你一個異常類型映射到另一個,這樣的方法可以拋出在同一抽象級別的方法本身定義的異常而不會丟棄重要的調試信息。
也就是說,如果你有一個從數據庫加載某些對象的方法,你可能反而需要一些ResourceLoadException
(上的相關方法抽象級別),而不是一個低級別的SQLException
即使是問題的原始來源。但是,如果您只是簡單地捕獲SQLException
並拋出ResourceLoadException
,則可能會丟失重要的調試信息。
因此,鏈接例外是一個很好的選擇。您會拋出一個「高級」異常,非常適合特定的方法,但將其與導致異常的異常鏈接起來。
否則,程序員可以在相同的代碼中捕獲兩個異常,而不是拋出一個新的Throwable實例嗎?
我不太關注你的推理。關鍵是他不應該在這個抽象層次上擔心SQLException
。
我認爲這個例子的原因是作者希望創建一個不依賴於某些特定底層系統(如SQL)的統一接口。因此,他將異常轉換爲更一般的形式,使實際實現對業務邏輯透明。
但是,在某些情況下,可能需要傳播像SQLException這樣的錯誤。這在基於拋出的異常需要採取不同操作的地方很有用。
優點是主叫方只需處理ResourceLoadException
而不是SQLException
。這樣,如果稍後將數據存儲更改爲訪問該文件的文件可能會導致IOException
。您不必返回並更改調用方處理的異常類型。這對你的調用者很有用,因爲調用者要以相同的方式處理異常。
loadResource
的調用者不需要知道如何加載這些資源的確切細節,或者至少不關心其失敗原因的細節。 (請記住它可能不是你寫的loadResources
,或者它可能是其他人需要使用loadResources方法)。
當你調用loadResource時,你應該關心的是它可能拋出ResourceLoadException異常。並非由於SQLException而導致實現細節失敗 - 這也可能隨着時間而改變,稍後有人可能會決定從其他地方加載可能會失敗的資源。
你只需要加載一些資源,如果它失敗,你需要處理,並且不處理潛在的MainframeHasCrashedException,FileNotFoundException和加載這些資源的其他十幾個原因可能會失敗。
現在,如果有些地方工作不及格,這是方便有導致失敗,如一個SQLException原始異常 - 所以有人通過日誌文件或淘類似可以通過檢查堆棧跟蹤
找出錯誤的原因如果loadResources也可能拋出其他異常,例如在這裏你不應該試圖捕獲Exception。一個UnautorizedException,當你調用loadResources時你可能不想處理這個問題 - 你可能想把這個異常傳播給可以處理UnautorizedException的其他調用者(也許提示用戶輸入一些憑證)。一個catch(Exception e)會吞下那個你真的無法在那裏處理的UnautorizedException。
第一個好處是封裝。 ResourceLoader可能是一個與多個實現的接口(例如一個從數據庫加載資源,另一個從文件系統加載它們),在運行時選擇要使用的實現。那麼調用者應該不知道爲什麼加載資源失敗的根本原因,但可能仍希望對資源加載失敗做出反應。如果接口聲明調用者可能希望以不同方式響應的兩個不同異常(例如,TransientResourceLoadFailureException(重試可能取消的地方)以及PermanentResourceLoadFailureException(重試地址已知不成功)),則此方法特別有用。
異常鏈接的第二個好處是鏈中的每個異常都可能有不同的消息,這允許包含用於調試的附加信息。在你的情況下,請注意ResourceLoadException的消息包含無法加載的資源的名稱,不保證包含在SQLException中,但可能需要重現該問題(某些數據庫並不完全知道特定的錯誤消息)。
這些好處是以編寫和維護catch塊爲代價的。您應該根據具體情況決定是否可以獲得成本。
爲什麼連鎖異常?
我們需要鏈接異常以使日誌可讀。
取1.下面的例子不鏈接和鏈接2,異常感覺不一樣
創建以下例外
class NoLeaveGrantedException extends Exception {
public NoLeaveGrantedException(String message, Throwable cause) {
super(message, cause);
}
public NoLeaveGrantedException(String message) {
super(message);
}
}
class TeamLeadUpsetException extends Exception {
public TeamLeadUpsetException(String message, Throwable cause) {
super(message, cause);
}
public TeamLeadUpsetException(String message) {
super(message);
}
}
class ManagerUpsetException extends Exception {
public ManagerUpsetException(String message, Throwable cause) {
super(message, cause);
}
public ManagerUpsetException(String message) {
super(message);
}
}
class GirlFriendOfManagerUpsetException extends Exception {
public GirlFriendOfManagerUpsetException(String message, Throwable cause) {
super(message, cause);
}
public GirlFriendOfManagerUpsetException(String message) {
super(message);
}
}
現在使用它們
1。無鏈接
public class MainClass {
public static void main(String[] args) throws Exception {
getLeave();
}
static void getLeave() throws NoLeaveGrantedException {
try {
howIsTeamLead();
} catch (TeamLeadUpsetException e) {
e.printStackTrace();
throw new NoLeaveGrantedException("Leave not sanctioned.");
}
}
static void howIsTeamLead() throws TeamLeadUpsetException {
try {
howIsManager();
} catch (ManagerUpsetException e) {
e.printStackTrace();
throw new TeamLeadUpsetException(
"Team lead is not in good mood");
}
}
static void howIsManager() throws ManagerUpsetException {
try {
howIsGirlFriendOfManager();
} catch (GirlFriendOfManagerUpsetException e) {
e.printStackTrace();
throw new ManagerUpsetException("Manager is in bad mood");
}
}
static void howIsGirlFriendOfManager()
throws GirlFriendOfManagerUpsetException {
throw new GirlFriendOfManagerUpsetException(
"Girl friend of manager is in bad mood");
}
}
2。鏈接
public class MainClass {
public static void main(String[] args) throws Exception {
getLeave();
}
static void getLeave() throws NoLeaveGrantedException {
try {
howIsTeamLead();
} catch (TeamLeadUpsetException e) {
throw new NoLeaveGrantedException("Leave not sanctioned.", e);
}
}
static void howIsTeamLead() throws TeamLeadUpsetException {
try {
howIsManager();
} catch (ManagerUpsetException e) {
throw new TeamLeadUpsetException(
"Team lead is not in good mood", e);
}
}
static void howIsManager() throws ManagerUpsetException {
try {
howIsGirlFriendOfManager();
} catch (GirlFriendOfManagerUpsetException e) {
throw new ManagerUpsetException("Manager is in bad mood", e);
}
}
static void howIsGirlFriendOfManager()
throws GirlFriendOfManagerUpsetException {
throw new GirlFriendOfManagerUpsetException(
"Girl friend of manager is in bad mood");
}
}
現在比較日誌
1.如果沒有鏈接
com.bskyb.svod.autoingest.GirlFriendOfManagerUpsetException: Girl friend of manager is in bad mood
at com.bskyb.svod.autoingest.MainClass.howIsGirlFriendOfManager(MainClass.java:61)
at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:52)
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:43)
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
com.bskyb.svod.autoingest.ManagerUpsetException: Manager is in bad mood
at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:55)
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:43)
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
com.bskyb.svod.autoingest.TeamLeadUpsetException: Team lead is not in good mood
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:46)
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
Exception in thread "main" com.bskyb.svod.autoingest.NoLeaveGrantedException: Leave not sanctioned.
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:37)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
2.鏈接
Exception in thread "main" com.bskyb.svod.autoingest.NoLeaveGrantedException: Leave not sanctioned.
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:36)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
Caused by: com.bskyb.svod.autoingest.TeamLeadUpsetException: Team lead is not in good mood
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:44)
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
... 1 more
Caused by: com.bskyb.svod.autoingest.ManagerUpsetException: Manager is in bad mood
at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:52)
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:42)
... 2 more
Caused by: com.bskyb.svod.autoingest.GirlFriendOfManagerUpsetException: Girl friend of manager is in bad mood
at com.bskyb.svod.autoingest.MainClass.howIsGirlFriendOfManager(MainClass.java:58)
at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:50)
... 3 more
好。我的觀點是:以下更改會出現什麼問題(僅顯示必要的更改)? `try {} catch(SQLException e){} catch(ResourceLoadException f){}`。但我理解你有關於更密切相關的異常的觀點。但是現在我的問題是,如果自定義異常與實際異常無關,即異常實際上是「SQLException」而不是「ResourceLoadException」,那麼異常處理代碼可能是錯誤指導? – 2011-02-16 19:18:39
該代碼更改沒有任何錯誤,但正如我所說的,根本沒有必要在該抽象級別捕獲「SQLException」。例如,如果有兩個資源加載類:`MysqlResourceLoader`和`FileResourceLoader`,它們共享一個通用接口`ResourceLoader`。那麼`loadResource`方法顯然不應該被聲明爲拋出`SQLException`。 (如果我給你一個`ResourceLoader`並且你不知道它是實際類型呢?) – aioobe 2011-02-16 19:31:19
問題是你可能有一個接口在抽象層面拋出一個特定的異常類型。在實現該接口時可能需要捕獲SQLException或其他。接口的全部要點就是堅持下去,不需要改變它,無論實現的內容是什麼......如果這是有道理的。另外,在這種情況下,父類將不知道如何處理SQLException。它需要做的唯一事情就是總結「我們被搞砸了」,打印出一個錯誤,讓用戶修復它。 – user606723 2011-02-16 19:43:07