2014-10-22 77 views
4

我發現了一些得體通過合理的Eclipse JDT但似乎並沒有被定義任何地方:Java 8 lambda:默認情況下是自動推斷的異常RuntimeException?

<!-- language: lang-java --> 

public static <T, TException extends Exception> void iterateEx(
     Iterable<T> iterable, PredicateEx<T, TException> step) throws TException 
{ 
    for (T item : iterable) 
    { 
     if (step.testEx(item)) 
     { 
      ThreadExt.yield(); // sleep 0.001s 
     } 
    } 
} 

當我打電話用的λ爲PredicateEx ,未指定TException假設的方法如果lambda拋出任何東西,則爲RuntimeException。我在Eclipse JDT中找到了這段代碼,但它是lambda類型推斷中的一個明確定義的行爲,還是隻是在編譯器實現中做出的一些決定?因爲默認的異常也可能是Exception(= TException的上限),我很擔心,因爲我要重寫所有函數接收方法來正確處理檢查的異常。

呼叫者的實例是這樣的:

<!-- language: lang-java --> 

iterateEx(listOfResultSet, rs -> true); // throws RuntimeException, no try-catch required 
iterateEx(listOfResultSet, rs -> rs.getBoolean("SOME_COLUMN")); // throws SQLException 

的PredicateEx是謂詞的變體,其允許例外的投擲:

<!-- language: lang-java --> 

@FunctionalInterface 
public interface PredicateEx<T, TException extends Exception> 
{ 
    boolean testEx(T t) throws TException; 
} 
+0

這不是一個真正的lambda問題 - 任何行爲都將在[規範的泛型部分]中指定(http://docs.oracle.com/javase/specs/jls/se8/html/jls-8。 HTML#d5e13058)。 Java重寫方法/實現方法來縮小異常聲明是正常的。 – McDowell 2014-10-22 07:34:00

+0

它與來自lambda的類型推斷有關 - 如果沒有引發或者拋出多於一種類型的異常,應該推斷出的TException是什麼? – AqD 2014-10-22 12:42:02

回答

1

類型推斷是用Java語言規範的chapter 18說明。在18.2.5中描述了檢查的例外和throws子句的特定情況。本節指定throws子句中應包含哪些類型的邊界推斷變量。對於你描述的情況最有趣的部分是

否則,假設E1, ..., En是函數類型的throws子句中不屬於正確類型的類型。如果lambda表達式是隱式類型的,那麼讓它的參數類型爲函數類型的參數類型。如果lambda體是poly表達式或包含poly結果表達式的塊,則讓目標返回類型爲函數類型的返回類型。假設X1, ..., Xm是lambda體可以拋出的檢查異常類型(§11.2)。然後有兩種情況:

  • ...

  • 如果n > 0,約束簡化爲一組的分型的限制:所有i (1 ≤ i ≤ m),如果Xi是不是在任何適當類型的子類型throws子句,則對於全部j (1 ≤ j ≤ n),‹Xi <: Ej›,約束條件包括。另外,對於全部j (1 ≤ j ≤ n),約束條件減少到約束throws Ej

這是什麼意思?這意味着throws子句中的每個推理變量(即要推斷的異常類型)必須是lambda主體拋出的每個檢查異常的超類型。聽起來很奇怪,對吧?但是JLS中有一個註釋:

請注意,處理多個推理變量出現在函數類型的throws子句中的情況不是完整性保留。任何一個變量本身都可以滿足約束條件,即每個檢查的異常都被聲明,但是我們無法確定哪個是預期的。所以,爲了可預測性,我們對它們進行約束。

這就是關於異常類型推斷的一般方面的部分。現在我們來看看JLS關於「默認」異常類型的說法。

部分18.4指定如何從類型邊界獲取「最終」類型。它有這個項目(我會忽略周圍的文字,以避免所有段落複製):

  • 如果αi有一個或多個合適的下限,L1, ..., Lk,然後Ti = lub(L1, ..., Lk)(§4.10.4)。
  • 否則,如果綁定集包含拋出αi,和αi適當的上界,頂多ExceptionThrowableObject,然後Ti = RuntimeException
  • 否則,其中αi具有適當的上限U1, ..., Uk,Ti = glb(U1, ..., Uk)(§5.1.10)。

這就是它!正如你所建議的那樣,當throws子句中的異常類型沒有其他類型綁定到RuntimeException時,它變成了「最終」類型。

+0

你參與java lambda項目嗎?我想報告一些錯誤。 – momomo 2014-12-18 14:41:42

+1

@momo請在[bugreport.java.com](http://bugreport.java.com/)報告錯誤。在第一個表單中,選擇類型:「Bug」,類別:「Java平臺標準版」,子類別:「javac編譯器」(用於與lambda相關的問題),您使用的版本和您的操作系統。然後填寫錯誤詳細信息表單。你也可以檢查打開的錯誤[這裏](https://bugs.openjdk.java.net/issues/?jql=project%20%3D%20JDK%20AND%20issuetype%20%3D%20Bug)來查看問題是否存在你遇到的是已知的。 – 2014-12-18 22:18:49