[英]“Specializing” a subtype's method to throw a checked exception?
在我的Java項目中,我有以下類/接口層次結構:
public interface ProductSearcher {
Set<Product> search(String request);
}
public interface OnlineProductSearcher extends ProductSearcher {
}
public interface DatabaseProductSearcher extends ProductSearcher {
}
OnlineProductSearcher
在某個遠程機器上搜索產品(例如,實現使用HTTP),而DatabaseProductSearcher
在我的本地機器中搜索產品(例如,實現使用JPA)。
事實證明, OnlineProductSearcher
可能在搜索產品時遇到問題,因為遠程機器已關閉,我的請求是速率限制的,5xx,4xx和諸如此類的響應。
所以我有想法讓我的OnlineProductSearcher
實現在出現與遠程機器相關的問題時拋出RemoteMadeProblemsException
。
因為我想強制任何OnlineProductSearcher
用戶優雅地處理這些異常而不要忘記這樣做,我使RemoteMadeProblemsException
成為一個已檢查的異常 ,即RemoteMadeProblemsException extends Exception
。
所以我一直認為重新定義OnlineProductSearcher
是這樣的:
public interface OnlineProductSearcher extends ProductSearcher {
Set<Product> search(String request) throws RemoteMadeProblemsException;
}
但是在Java中,不可能從子類型中的超類型重新聲明/約束方法(Eclipse告訴我“ Exception RemoteMadeProblemsException與ProductSearcher.search(String)中的throws子句不兼容 ”)
現在我看到兩種解決方案:
ProductSearcher.search(String)
以拋出RemoteMadeProblemsException
。 RemoteMadeProblemsException
擴展RuntimeException
並且沒有OnlineProductSearcher.search(String)
聲明一個throws
子句。 我覺得這兩種方案都不合適
DatabaseProductSearcher.search
任何用戶捕獲/拋出一個沒有意義的RemoteMadeProblemsException
(畢竟它是一個本地數據庫)。 OnlineProductSearcher.search(String)
並忘記嘗試捕獲RemoteMadeProblemsException
,讓異常失敗並OnlineProductSearcher.search(String)
。 什么是更好的解決方案“只有一些子類型可能會拋出異常”的問題?
你遇到的問題是:
ProductSearcher x = new OnlineProductSearcher();
這是完全合法的語法,現在如果有人調用x.method()
,Java就無法知道該檢查的異常。
這就是為什么子類只能使實現更具體。 他們可以返回子類並接受超類,但不能反過來。 這是因為要求對super方法的任何調用對子類方法也是有效的。
例如,如果:
Number process(Integer i) {
}
是一個超類然后一個有效的子類是:
Integer process(Number i) {
}
因為在超類中對每個process
調用在子類中也是有效的。 完全相同的參數適用於throws
聲明。 通過使子類拋出一個已檢查的異常,您無法將其視為具有與超類中相同簽名的方法。
解決您的困境的方法是定義一個更通用的異常ProductSearcherException
並讓ProductSearcher
拋出該異常。
然后,您的OnlineSearcherException
將OnlineSearcherException
ProductSearcherException
並且您的throw聲明變得合法。
你可以做的一件事就是改進事物包括三個班而不是一個班:
這確實削弱了人們做ProductSearcher x = new LocalProductSearcher
,然后使用更通用的類(因為他們需要捕獲異常),但對於任何使用LocalProductSearcher
,他們永遠不需要捕獲。
請注意,即使在本地情況下,您可能會發現自己需要在將來拋出異常,因此擁有它們並不可怕。
恕我直言你應該將throws Exception
添加到你的超級接口(可能還有一些更精致的版本,而不僅僅是Exception)。
原因是如果你沒有聲明throws異常,那么你的契約是:在正常執行下,沒有實現這個方法應該拋出異常。 在你的程序中,情況顯然並非如此,因為遙控器可能會遇到問題。
你不在數據庫版本中添加例外的原因是愚蠢的:數據庫今天是本地的,但明天可能是遠程的。 而本地數據庫也可能存在問題。
如果您真的不想從DatabaseProductSearcher版本中捕獲異常,那么您需要將其作為自身引用,而不是作為超接口引用,並重新定義DatabaseProductSearcher中的方法以不拋出任何內容。 然后,當您通過該接口引用它時,您不會被強制捕獲任何內容,因為編譯器現在知道此版本是安全的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.