JDK 12 ,JDK 13 , JDK 14 新特性 詳解

近年來,甲骨文做出了一些突破性的決定。 他們包括新的半年發佈模式與預覽功能和更短的發佈和反饋週期的新功能。 許可模式也發生了變化,Oracle JDK 不再免費提供。 這加劇了競爭,因此您現在可以從包括 Oracle 在內的各種供應商獲得免費的 OpenJDK 發行版。 自從 java11以來,它已經與 oraclejdk 實現了二進制兼容,並且採用開源許可證。

一年半以前,最後一個 LTS 版本 Java 11於2019年秋季發佈。 從那時起,隨後的兩個主要版本只有有限數量的新特性。 JDK 孵化器項目(Amber, Valhalla, Loom …) ,然而,正在致力於許多新想法,所以不足爲奇的是,剛剛發佈的 JDK 14的功能範圍再次顯著擴大。 即使只有少數人會在生產環境中使用新版本,您仍然應該關注新特性,並儘早就預覽功能提供反饋。 這是確保新特性投入生產直到下一個 LTS 版本最終完成的唯一方法,該版本將在2021年秋季以 Java 17的形式發佈。

下列Java增強建議(JEP)已經實現。在本文中,我們將從開發人員的角度來仔細研究感興趣的主題。

JEP 305: Pattern Matching for instanceof (Preview)
JEP 343: Packaging Tool (Incubator)
JEP 345: NUMA-Aware Memory Allocation for G1
JEP 349: JFR Event Streaming
JEP 352: Non-Volatile Mapped Byte Buffers
JEP 358: Helpful NullPointerExceptions
JEP 359: Records (Preview)
JEP 361: Switch Expressions (Standard)
JEP 362: Deprecate the Solaris and SPARC Ports
JEP 363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector
JEP 364: ZGC on macOS
JEP 365: ZGC on Windows
JEP 366: Deprecate the ParallelScavenge + SerialOld GC Combination
JEP 367: Remove the Pack200 Tools and API
JEP 368: Text Blocks (Second Preview)
JEP 370: Foreign-Memory Access API (Incubator)

JEP 305: Pattern matching for instanceof

自20世紀60年代以來,模式匹配語言的概念已經在各種編程語言中得到了應用。 其中最現代的例子是 Haskell 和 Scala。 模式是一個謂詞的組合,該謂詞匹配目標結構和該模式中的一組變量。 如果這些變量匹配,則爲它們分配相應的內容。 其目的是破壞對象,也就是將它們分解爲它們的組件。

到目前爲止,Java 只能區分 switch 語句中的數據類型 integer、 string 和 enum。 然而,隨着 Java 12中開關表達式的引入,邁向模式匹配的第一步已經邁出。 使用 Java 14,我們現在可以額外地使用模式匹配操作符 instanceof。 避免了不必要的強制轉換,減少的冗餘提高了可讀性。

例如,在此之前,必須按照以下步驟檢查空字符串或空集合:

boolean isNullOrEmpty( Object o ) {
  return == null ||
    instanceof String && ((String) o).isBlank() ||
    instanceof Collection && ((Collection) o).isEmpty();
}

現在您可以在使用 instanceof 檢查時直接將值賦給變量,並對其執行進一步調用:

boolean isNullOrEmpty( Object o ) {
  return o == null ||
    o instanceof String s && s.isBlank() ||
    o instanceof Collection c && c.isEmpty();
}

這種區別似乎微不足道,然而,Java 開發人員中的純粹主義者節省了一個小而煩人的冗餘。

開關表達式最早是在 Java 12和13中引入的,在這兩種情況下都是作爲一個預覽特性。 它們現已在 jep361中最後確定。 這爲開發人員提供了兩種新的語法變體,它們具有更短、更清晰和更不容易出錯的語義。 表達式的結果可以分配給變量,或者作爲方法的值返回(清單1)。

JEP 358: Helpful NullPointerExceptions

對空引用的無意訪問也是 Java 開發人員所擔心的。 根據託尼•霍爾爵士(Sir Tony Hoare)自己的說法,他發明的零Y引用是一個錯誤,其後果高達數十億美元。 這僅僅是因爲在20世紀60年代阿爾戈語的發展過程中,它是如此容易實現。

在 Java 中,編譯器和運行時環境都不支持處理零引用。 這些惱人的異常可以通過各種變通方法來避免。 最簡單的方法是將檢查設置爲零。 不幸的是,這個過程非常繁瑣,當我們需要它的時候我們往往會忘記它。 使用自 JDK 8以來包含的包裝器類 Optional,您可以通過 API 顯式地告訴調用者,一個值可以爲零,並且它必須對此進行響應。 因此,您不能再意外地遇到空引用,而必須顯式地處理可能爲空的值。 這個過程對於公共接口的返回值非常有用,但是也會消耗額外的間接層,因爲您總是需要解壓實際值。

在其他語言中,輔助工具早已構建到語法和編譯器中,比如Groovy中 NullObjectPattern 和 Safe Navigation 操作符(some?.method())。 在 Kotlin,可以明確區分可能不爲空的類型和可能作爲引用爲 null 的類型。 我們將來也必須使用 Java 中的 nullpointerexception。 但是,作爲預覽特性引入的有用的NullPointerExceptions可以簡化異常的故障排除。 爲了在拋出 NullPointerException 時插入必要的信息,必須在啓動時激活選項 -XX: + ShowCodeDetailsInExceptionMessages。 如果調用鏈中的一個值爲零,那麼您將收到一條有用的消息:

man.partner().name()

Result: java.lang.NullPointerException: Cannot invoke "Person.name()" because the return value of "Person.partner()" is null

Lambda表達式需要特殊處理。 例如,如果lambda函數的參數爲零,則默認情況下將收到清單2所示的錯誤消息。要顯示正確的參數名稱,必須使用-g:vars選項編譯源代碼。 結果如下:

java.lang.NullPointerException: Cannot invoke "Person.name()" because "p" is null

Listing 2 清單2

Stream.of( man, woman )
  .map( p -> p.partner() )
.map( p -> p.name() )
.collect( Collectors.toUnmodifiableList() );

Result: java.lang.NullPointerException: Cannot invoke "Person.name()" because is null "

不幸的是,當一個空參數時,目前沒有方法引用的指示:
但是,如本例所示,如果將每個流方法調用放在新行中,那麼麻煩的代碼行可以很快地縮小範圍。 NullPointerExceptions在自動裝箱/拆箱中也具有挑戰性。 如果在這裏也激活了編譯器參數-g:vars,您還將收到新的有用的錯誤消息(清單3)。

Listing 3 清單3
int calculate() {
  Integer a = 2, b = 4, x = null;
  return a + b * x;
}
calculate();
Result: java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because "x" is null

JEP 359: Records

也許最令人興奮的同時也是最令人驚訝的創新是記錄類型的引入 。 它們是在Java 14發行中相對較晚實現的,是一種類聲明的限制形式,類似於枚舉。 記錄是在Valhalla項目中開發的。 與Kotlin中的Data Classes和Scala中的Case Classes有某些相似之處。 緊湊的語法可能會使Lombok之類的庫在將來過時。 Kevlin Henney還看到了以下優點:“我認爲Java記錄功能的有趣的副作用之一是,實際上,它將幫助揭示多少Java代碼實際上是面向 getter / setter而非面向對象的。” 一個人有兩個字段的簡單定義可以在這裏看到 :

public record Person( String name, Person partner ) {}

一個帶有附加構造函數的擴展變量,因此只有字段name 是強制的,也可以實現:

public record Person( String name, Person partner ) {
  public Person( String name ) { this( name, null ); }
  public String getNameInUppercase() { return name.toUpperCase(); }
}

編譯器生成一個不可變類,除了這兩個屬性和它自己的方法之外,它還包含訪問器的實現(沒有 getter!) 、構造函數 equals / hashcode 和 toString (清單4)。

Listing 4 清單4
public final class Person extends Record {
  private final String name;
  private final Person partner;

  public Person(String name) { this(name, null); }
  public Person(String name, Person partner) { this.name = name; this.partner = partner; }

  public String getNameInUppercase() { return name.toUpperCase(); }
  public String toString() { /* ... */ }
  public final int hashCode() { /* ... */ }
  public final boolean equals(Object o) { /* ... */ }
  public String name() { return name; }
  public Person partner() { return partner; }

使用的行爲符合預期,您無法從調用方判斷記錄類型是實例化的(清單5)。

Listing 5 清單5
var man = new Person("Adam");
var woman = new Person("Eve", man);
woman.toString(); // ==> "Person[name=Eve, partner=Person[name=Adam, partner=null]]"

woman.partner().name(); // ==> "Adam"
woman.getNameInUppercase(); // ==> "EVE"

// Deep equals
new Person("Eve", new Person("Adam")).equals( woman ); // ==> true

總結

Java沒有死,Java萬歲! 半年兩次的OpenJDK版本使語言和平臺都受益。 這次,新功能比Java 12和13還要多。而且,仍有許多功能需要在將來的版本中實現。 因此,我們的Java開發人員不會感到無聊,並且未來的前景仍然一片光明。 到2020年9月,我們可以預見Java 15的到來。

【關注公衆號 “碼農架構”】回覆:“資料” 最新面試資料整理文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章