我注意到一些Java異常類僅在類的名稱上有所不同,並且不添加任何新的功能。例如,大多數例外似乎都會覆蓋Exception() or Exception(String message)
。這違背了繼承原則,即: - 繼承添加新的功能。什麼時候應該創建一個新的異常類
創建一個新的Exception類有什麼好的理由?
我注意到一些Java異常類僅在類的名稱上有所不同,並且不添加任何新的功能。例如,大多數例外似乎都會覆蓋Exception() or Exception(String message)
。這違背了繼承原則,即: - 繼承添加新的功能。什麼時候應該創建一個新的異常類
創建一個新的Exception類有什麼好的理由?
異常是一種特殊情況。在他們的情況下,繼承不是添加新的功能,而是添加新的錯誤類。這可以讓你的代碼抓住特定類型的錯誤而忽略其他錯誤。
假設你正在編寫一個大型項目。你有一個Data組件,並且你有一個Display組件。他們都可能以各種方式失敗,並且你想爲這些失敗拋出異常。 Display組件不關心Data組件產生的異常,反之亦然。如果所有的類只是拋出了Exception
,那麼就沒有辦法找出異常來自哪裏。但是,如果您將Exception
與DataException
和GraphicsException
一起繼承,即使它們沒有添加新功能,現在也可以拋出並捕獲這些特定類型的異常,即圖形組件可以捕獲GraphicsException
,而不必處理數據異常。
不要忘記繼承(例如MyNumericDataException擴展MyDataException)可以讓您的異常處理架構真正乾淨地將各種類型的異常組合在一起。 – 2009-12-31 18:01:04
那麼,使用子類來區分異常原因似乎對繼承的使用不直觀。還有其他方法可以識別類型。然而,真正的問題是語言的限制,catch/throw的方式固有地根據類的類型進行區分。 – VDev 2009-12-31 18:49:26
是的,但Java類的單一繼承非常適合建立抽象層次結構。因此,允許對異常做出反應的程度,即爲更高層次的抽象捲起例外。 – harschware 2009-12-31 18:57:13
您可以通過類型捕獲異常,並且具有與基本Exception類別相同的特定類型的異常,這使您能夠在異常處理中做到精確。
我認爲它通過增加異常處理代碼的特異性直接增加了新的功能。
當API的用戶可能需要有條件地捕獲它時(或者checked exceptions在throws
中指定了不同的特定類型),可以添加一個新的異常類。
括號內容是......令人困惑。在Java中,檢查異常的「檢查」是由編譯器完成的,而不是由你的代碼完成的。 – 2009-12-31 18:31:11
我會重申那一點。 – 2009-12-31 18:48:53
此重命名發生以消除歧義wrt。發生的錯誤。例如
Foo getFoo() throws FooNotFoundException
將是明確的指示Foo
不能被發現,而不是(什麼?)一些非法狀態,或數據庫連接錯誤或相似的,你可以選擇代碼(或沒有)爲特別是錯誤。如果您選擇拋出更通用的異常,則不太清楚(編程)發生了什麼。
這是不好的形式,只是趕上任何異常,因爲你不僅不知道它來自哪裏,但你可能會防止自己在發生錯誤時正確處理錯誤。如果你只是捕獲任何類型的異常並以相同的通用方式處理它,那麼你可能會隱藏軟件中的其他問題,甚至引入新的異常。所以,從技術上說,子類異常確實增加了新功能。
如果您希望爲特定條件提供錯誤處理,請使用新的異常類型。看看java.io.IOException的,你會看到下面的子類:
ChangedCharSetException
CharacterCodingException
CharConversionException
ClosedChannelException
EOFException
FileLockInterruptionException
FileNotFoundException
FilerException
HttpRetryException
IIOException
InterruptedIOException
InvalidPropertiesFormatException
JMXProviderException
JMXServerErrorException
MalformedURLException
ObjectStreamException
ProtocolException
RemoteException
SaslException
SocketException
SSLException
SyncFailedException
UnknownHostException
UnknownServiceException
UnsupportedDataTypeException
UnsupportedEncodingException
UTFDataFormatException
ZipException
假設你想從文件中讀取,你可以得到一個通用的IOException異常,一個FileNotFoundException異常,和EOFException類。你可能想要以不同的方式處理每一種情況。如果你只有IOException,你將不得不做一些事情,比如查看錯誤消息,然後執行if/else語句來確定實際錯誤是什麼,以便向用戶顯示合理的消息。有了例外的層次結構,您可以更輕鬆地處理這些情況。
在這種情況下,繼承添加的功能與catch語句有關,它可以按類型區分。通常按類型區分子類被認爲是不好的做法,但是異常處理就是一個例外。
它肯定會導致奇怪的情況(例如具有相同邏輯的多個catch語句),正如您按照類型區分事物時所期望的那樣,但這是語言的限制。
我推薦閱讀Effective Java第9章的全部或大部分內容。特別是第60項:「贊成使用標準例外」和第61項:「投入適用於抽象的例外」。
編輯1:或Items 42 and 43在第一版。
爲任何類型創建一個例外是非常愚蠢的。也許你應該爲不同的層(DAO,Service等)或不同的操作(創建記錄,重複記錄等)創建一個異常。
如果您需要或想要區分特定的錯誤情況與代碼中的其他錯誤,那麼對適當的異常進行子類化是有意義的。你應該不是需要偷看錯誤信息,以確定出了什麼問題 - 這隻適用於人眼。
另外請注意,一個正確命名的異常可能足以讓維護人員的眼睛推斷出當診斷堆棧跟蹤時出了什麼問題。一個典型的例子是ArrayOutOfBoundsException。
繼承只改變一個例外的名稱是不是一個最佳實踐恕我直言。但是,這樣做可以創建一個異常層次結構,以便在各個抽象層上提供響應度,這是一種很好的做法。換句話說,創建新的Exception類有充足的理由和不好的理由! – harschware 2009-12-31 19:00:04