在 最新的JEP 上顯示,Java枚舉將增強泛型支持,并能將方法添加到單個項目上去。這兩個功能可以通過一次更改進行交付,原因是它們捆綁在了一起。更改僅僅會影響到Java編譯器,因此不需要運行時更改。雖然沒有目標版本,但可能會在Java 10中呈現更改。
一開始這個更改沒有得到很大的肯定,比如杰出的Java Champions Joshua Bloch就其實用性提出了質疑。然而,通過進一步的討論和新用例的介紹幫助它逐步獲得了支持。
以防你沒有看到我對 @BrianGoetz 的回應,我已經看到了JEP列出的介紹,我也撤回了我先前對這個變更的不看好觀點。用例: https://t.co/O1tJO8oSCp
——Joshua Bloch (@joshbloch) 2016年12月7日
讓我們一起通過JEP中舉出的用例和一些其他討論來總結一下這次變更給開發者帶來了什么改變。Java Champion Lukas Eder提出了一個 StackOverflow的問題 ,介紹了通過配置文件、web會話或類似類型安全的方式檢索和設置屬性的用例。帶有泛型支持的枚舉讓我們可以指示一組可用的鍵和它們相關聯的類型:
public enum Keylt;Tgt; {HOSTlt;Stringgt;,PORTlt;Integergt;,SCORElt;Doublegt;}public interface PropertiesStore { public lt;Tgt; void put(Keylt;Tgt; key, T value); public lt;Tgt; T get(Keylt;Tgt; key);}
現在,這些鍵可以安全地在屬性存儲中進行檢索和存儲,因為下面的表達式將無法編譯:
put(PORT, “not a number”); // error, type mismatch: PORT is Keylt;Integergt; // “not a number” is String
另一方面,允許單個項目有自己的方法可以幫助定義只適用于某些屬性的操作。根據JEP 301所述,上述定義可以擴展如下:
public enum Keylt;Tgt; {HOSTlt;Stringgt;,PORTlt;Integergt;,SCORElt;Doublegt; { double normalise(double x) { // score normalisation logic return result; }}}
根據當前的枚舉,所有項目都有通用類型Key,這意味著方法normalise將不可見。但是在這項工作完成后,編譯器將會保留這類型信息,這代表著以下的將為真:
SCORE.normalise(5.37); // compilesHOST.normalise(5.37); // error: neither HOST nor Key have normalise
要實現這一點,需要改變計算各個枚舉項目的靜態類型的方式。正如讀者可能知道的一樣,枚舉在Java 5中僅僅作為純粹的語法上的甜頭而添加:JVM對枚舉沒有任何特殊的處理,而是由編譯器將枚舉轉換為帶有靜態對象的普通類,然后將其編譯為字節碼。拋開一切技術方面的問題,下面的枚舉:
public enum Colour { RED, GREEN, BLUE}
由編譯器粗糙地進行了轉換,如下(這不是一個非常準確的表達,但是足以解釋清楚):
public class Colour extends Enum {public static final Colour RED = new Colour();public static final Colour GREEN = new Colour();public static final Colour BLUE = new Colour(); private Colour() {}}
由于所有項目的類型是Colour,任何項目特定的方法和類型信息都會丟失。 JEP 301
要做的是確定使用通用枚舉類型不足以表示單個項目的情況,在這種情況下生產更多更具體的類型,如 Colour$RED
、 Colour$GREEN
和 Colour$BLUE
。
增強的枚舉甚至可以從JDK其他部分正在進行的工作中受益。一方面,局部變量類型推斷可以讓開發人員獲得由編譯器創建的更清晰的類型,即使這些類型的確切形式在編寫代碼的時候是未知的,這意味著上面的代碼可能是以下這樣的:
var s = Key.SCORE; // type of s derived as Key$SCOREs.normalise(8.29); // method normalise can be accessed
另一方面,一些證據和用例都表示枚舉中的泛型可能更加廣泛地使用于原始類型,這是相當低效的(JVM必須為每個原始類型使用 裝盒后對應類型 )。這可以通過 Valhalla項目 中 處理原始類型的泛型 這個部分消除障礙,并使其可用于大規模使用。
Tags: Java
文章來源:http://www.infoq.com/cn/news/2017/01/java-enhanced