2015-08-27 44 views
13

我構建了一些我不太瞭解的東西 - 我不知道它是如何工作的。我已經熟悉了這個multicatch explaination article確定編譯時multicatch異常類型

考慮這兩種例外和代碼:

public class MyException1 extends Exception { 
    // constructors, etc 
    String getCustomValue(); 
} 

public class MyException2 extends Exception { 
    // constructors, etc 
    String getCustomValue() { return "foo"; } 
} 

try { 
    //... 
} catch (MyException1|MyException2 e) { 
    e.getCustomValue(); // won't work, as I expected 
} 

我就不能叫getCustomValue(),儘管方法是相同的,因爲Java裏面上述try/catch被認爲實際上是鑄造MyException1/2Exception(這就是我理解文檔的方式)。

但是,如果我介紹了一個這樣的接口:

public interface CustomValueGetter { 
    String getCustomValue(); 
} 

public class MyException1 extends Exception implements CustomValueGetter /*...*/ 
public class MyException2 extends Exception implements CustomValueGetter /*...*/ 

,並把它添加到兩個例外,Java的其實是能夠允許我使用這個方法。然後調用,這是有效的:

try { 
    //... 
} catch (MyException1|MyException2 e) { 
    e.getCustomValue(); // does work 
} 

總之,我的問題是:什麼是真正發生在這裏:(MyException1|MyException2 e)

什麼是e

  • 選擇作爲e類型最接近的超? This question asks about it這就是所謂的答案。如果是這樣,那麼爲什麼當我訪問e時接口CustomValueGetter「可見」?在我的情況下,它不應該是eException

  • 如果不是,如果真實的類是MyException1MyException2爲什麼我不能簡單地調用相同的方法可用於這兩個類?

  • e動態生成的類的一個實例,它實現了這兩個異常的所有常見接口,並且是最接近的普通超類類型?

回答

4

正如Ischuetze所說,e正在尋找兩個例外共享的類或接口。在你的第一個例子中,儘管有Exception類,但仍然無法找到共享類,因此它只能使用它提供的方法。

將您的示例更改爲此代碼將能夠再次編譯。

public class MyException12 extends Exception { 
    public String getCustomValue(){ return "boo"; }; 
} 

public class MyException1 extends MyException12{ 
    public String getCustomValue() { return "foo"; }; 
} 

public class MyException2 extends MyException12{ 
    // constructors, etc 
    public String getCustomValue() { return "foo"; }; 
} 

如與接口的例子中,異常通知既MyException1MyException2MyException12,因此能夠使用it's功能。

Here是一個SO問題,回答了整個問題以及e的類型。

從答案的鏈接報價:

更改異常類型的處理影響類型系統有兩種方式:除了對所有類型的檢查進行通常的類型,異常類型進行額外的編譯時間分析。爲了類型檢查的目的,用斷言聲明的catch參數具有類型lub(t1,t2,...)(JLSv3§15.12.2.7),其中ti是catch子句聲明處理的異常類型。非正式地,lub(最小上限)是所討論類型中最具體的超類型。在multi-catch異常參數的情況下,由於所有捕獲的異常的類型必須是Throwable的子類,因此總是存在所討論的類型的最小上限。因此,Throwable是所討論類型的上限,但它可能不是最小上限,因爲Throwable的某些子類可能是所討論類型的超類(因此也是超類型),並且所討論的異常類型可能實現一個通用接口。 (一個Iub可以是超類和一個或多個接口的交集類型。)爲了進行異常檢查(JLSv3§11.2),拋出最終或有效的最終catch參數的throw語句(JLSv3§11.2.2)是視爲投擲精確的那些異常類型:

+0

如果在答案中發佈的鏈接的接受答案是正確的,那麼我使用的接口永遠不應該在'e'中解析,因爲這兩個例外的超類都不會實現它。 – Dariusz

+1

@Dariusz我edid並引用了另一個問題的答案中的鏈接,通知後面的部分說:'一個Iub可以是一個超類和一個或多個接口的交集類型。' – SomeJavaGuy

+1

太糟糕了,措辭沒有使它轉化爲實際的Java語言文檔(這是非常模糊寫的)。我猜最接近的是[交集類型](https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.9)的描述,其中提到「類型推斷( §15.12.2.7)「,對[catch子句]的描述也是如此(https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20-510 )。 – Andreas

4

在第一個代碼示例中的Java不能自動推斷,這兩個MyException1MyException2實現該功能getCustomValue。所以e是兩者類型層次結構中最大的共同點;即Exception,並且不具備功能getCustomValue。因此,它不工作。

Java是強類型的,儘管這些函數被命名爲similary,但它們與在相同類型中聲明的功能並不相同。

在第二個代碼中,兩個例外都實現了CustomValueGetter。因此,e是實現getCustomValue的最大共同標準CustomValueGetter

2

挖掘@Kevin Eshche的JLS鏈接我似乎已經找到了正確的答案。

在編譯時e實際上是一個最小上界,它定義在JLS-15.12.2.7

文檔的摘錄:

計算交集比人們第一 實現更復雜。假定一個類型參數被約束爲一個泛型類型的兩個不同調用的超類型 ,比如List和 List,那麼天真的交集操作可能會產生Object。 但是,更復雜的分析會生成一個包含 列表的集合。同樣,如果一個類型參數T被約束爲兩個不相關的接口I和J的超類型,我們可以推斷T必須是 是對象,或者我們可以獲得I的更緊密的邊界。這些問題 在更多本節後面的細節。

總之,它是所有|「d例外的最接近的共同父的class(在我的情況下,Exception),它實現了所有接口的例外做(在我的情況,CustomValueGetterSerializable) 。