JDK 15已經在2020年9月15日發佈!詳情見 JDK 15 官方計劃。下面是對 JDK 15 全部新特性的詳細解析!html
JEP 339: Edwards-Curve Digital Signature Algorithm (EdDSA)java
與其餘簽名方案相比,EdDSA 具備更高的安全性和性能,而且已有不少其餘加密庫(如 OpenSSL 和 BoringSSL)支持此簽名方案。EdDSA 是 TLS 1.3的可選組件,且是 TLS 1.3 中僅有的三種簽名方案之一。用戶能夠沒必要再使用第三方庫了。git
JEP 360: Sealed Classes (Preview)github
在 Java 語言中,代碼的重用是經過類的繼承實現的:多個子類能夠繼承同一個超類(並重用超類的方法)。可是重用代碼並非類層次結構的惟一目的,有時類層次結構僅僅是對某個領域的建模。以這種方式使用類層次結構時,限制子類集合能夠簡化建模。算法
好比在圖形庫中,Shape 類的開發者可能只但願有限個數的類擴展 Shape 類,開發者並不想爲未知子類編寫防護代碼。之前的 Java 並不會限制 Shape 類的擴展屬性,Shape 類能夠擁有任意數量的子類。在封閉類(Sealed Classes)中,類層次結構是封閉的,可是代碼仍然能夠在有限範圍內重用。shell
經過 sealed
修飾符將一個類聲明爲密封類,permits子句指定容許擴展密封類的類。例以下面的 Shape 類聲明指定了三個可擴展的子類。編程
package com.example.geometry; public abstract sealed class Shape permits Circle, Rectangle, Square {...}
在子類數量不多時,在密封類的源文件中聲明子類會很方便。當以這種方式聲明子類時,密封類能夠省略 allows 子句,同時 Java 編譯器將從源文件中推斷容許的子類。例以下面的例子:安全
package com.example.geometry; abstract sealed class Shape {...} ... class Circle extends Shape {...} ... class Rectangle extends Shape {...} ... class Square extends Shape {...}
密封類可讓代碼更簡潔,代碼能夠明確推斷出全部容許的子類。好比傳統的 if-else 和 instanceof 代碼編譯器分析起來很困難,沒法肯定子句是否覆蓋了全部容許的子類。下面的方法會致使編譯期錯誤:數據結構
int getCenter(Shape shape) { if (shape instanceof Circle) { return ... ((Circle)shape).center() ... } else if (shape instanceof Rectangle) { return ... ((Rectangle)shape).length() ... } else if (shape instanceof Square) { return ... ((Square)shape).side() ... } }
在以後支持模式匹配的版本中,編譯器能夠直接推斷出 Shape 全部容許的子類,不須要 default 語句。此外,若是缺乏子類的任意一個,編譯器就會報錯。多線程
int getCenter(Shape shape) { return switch (shape) { case Circle c -> ... c.center() ... case Rectangle r -> ... r.length() ... case Square s -> ... s.side() ... }; }
package java.lang.constant; public sealed interface ConstantDesc permits String, Integer, Float, Long, Double, ClassDesc, MethodTypeDesc, DynamicConstantDesc {...} // ClassDesc is designed for subclassing by JDK classes only public sealed interface ClassDesc extends ConstantDesc permits PrimitiveClassDescImpl, ReferenceClassDescImpl {...} final class PrimitiveClassDescImpl implements ClassDesc {...} final class ReferenceClassDescImpl implements ClassDesc {...} // MethodTypeDesc is designed for subclassing by JDK classes only public sealed interface MethodTypeDesc extends ConstantDesc permits MethodTypeDescImpl {...} final class MethodTypeDescImpl implements MethodTypeDesc {...} // DynamicConstantDesc is designed for subclassing by user code public non-sealed abstract class DynamicConstantDesc implements ConstantDesc {...}
JVM 在運行時識別密封類和接口,並防止未經受權的子類和子接口擴展密封類。
儘管 sealed 關鍵字是類修飾符,可是 ClassFile 中並無 ACC_SEALED 標誌。相反,密封類的類文件具備 PermittedSubclasses屬性,該屬性隱式指示密封修飾符,並顯式指定容許的子類:
PermittedSubclasses_attribute { u2 attribute_name_index; u4 attribute_length; u2 number_of_classes; u2 classes[number_of_classes]; }
java.lang.Class
將增長以下 public 方法:
隱藏類不能被其餘類的字節碼直接使用,適合在運行時生成類、並經過反射間接使用隱藏類的框架。
許多機遇 JVM 構建的語言都經過動態生成類,提升靈活性和效率。好比在 Java 語言中,javac 不會在編譯時將 lambda 表達式轉換成特殊的類文件,而是保存在字節碼中,該字節碼能夠把 lambda 表達式動態生成爲相應的對象。一樣地,非 Java 語言常常經過運行時生成動態代理,來實現語言的高級特性。
語言的實現者一般但願將動態生成的類,在邏輯上成爲靜態生成類的實現的一部分:
動態生成類僅是靜態生成類的實現細節
這一目標。不幸的是,類定義的標準 API(ClassLoader::defineClass 和 Lookup::defineClass)並不在乎該類的字節碼是動態生成(在運行時)仍是靜態生成(在編譯時)的。若是標準 API 能夠定義沒法被發現,且具備有限生命週期的隱藏類,則動態生成類的 JDK 內部和外部框架均可以定義隱藏類,這樣作能夠提升 JVM 語言實現的效率。好比:
JEP 372: Remove the Nashorn JavaScript Engine
Java 11 中已經將該引擎標記爲廢棄,並明確表示要在未來的版本中刪除它。Nashorn JavaScript 引擎最開始是 JDK 8 經過 JEP 174 繼承的,用來代替 Rhino 腳本引擎,當時 Nashorn JavaScript 引擎是 ECMAScript-262 5.1 標準的完整實現。可是隨着 ECMAScript 語言構造以及 API 的修改,咱們發現 Nashorn 難以維護。
JDK 的兩個模塊會永久刪除:
JEP 373: Reimplement the Legacy DatagramSocket API
Java.net.DatagramSocket 和 java.net.MulticastSocket API 重構了基礎實現,使得其更易於維護和調試。新的實現能更好地適應虛擬線程的工做。
JEP 374: Disable and Deprecate Biased Locking
默認狀況下禁用偏向鎖,並廢棄全部相關的命令行。
偏向鎖是 HotSpot 虛擬機使用的一項優化技術,可以減小無競爭鎖定時的開銷。偏向鎖的目的是假定 monitor 一直由某個特定線程持有,直到另外一個線程嘗試獲取它,這樣就能夠避免獲取 monitor 時執行 cas 的原子操做。monitor 首次鎖定時偏向該線程,這樣就能夠避免同一對象的後續同步操做步驟須要原子指令。從歷史上看,偏向鎖使得 JVM 的性能獲得了顯著改善。
可是過去看到的性能提高,在如今看來已經不那麼明顯了。受益於偏向鎖的應用程序,每每是使用了早期 Java 集合 API的程序(JDK 1.1),這些 API(Hasttable 和 Vector) 每次訪問時都進行同步。JDK 1.2 引入了針對單線程場景的非同步集合(HashMap 和 ArrayList),JDK 1.5 針對多線程場景推出了性能更高的併發數據結構。這意味着若是代碼更新爲使用較新的類,因爲沒必要要同步而受益於偏向鎖的應用程序,可能會看到很大的性能提升。此外,圍繞線程池隊列和工做線程構建的應用程序,性能一般在禁用偏向鎖的狀況下變得更好。
偏向鎖爲同步系統引入了許多複雜的代碼,而且對 HotSpot 的其餘組件產生了影響。這種複雜性已經成爲理解代碼的障礙,也阻礙了對同步系統進行重構。所以,咱們但願禁用、廢棄並最終刪除偏向鎖。
JEP 375: Pattern Matching for instanceof (Second Preview)
經過對 instanceof 運算符進行模式匹配,來增長 Java 語言。模式匹配可使應用程序更簡潔、安全地提取特定對象。
不少程序都會判斷一個表達式是否具備某種類型或結構,而後有條件地進一步處理,好比下面的 instanceof-and-cast 用法:
if (obj instanceof String) { String s = (String) obj; // use s }
上述代碼作了 3 件事:
這種模式很簡單,可是這樣的寫法並非最優的。第 2 步的類型轉換是重複的,同時重複可能會帶來錯誤。模式匹配容許簡明地表達對象的所需「形狀」(模式),並容許各類語句和表達式針對其輸入來測試「形狀」(匹配)。從 Haskell 到 C# 等不少語言都接受了模式匹配。
在下面的代碼中,短語 String s 是類型測試模式:
if (obj instanceof String s) { // can use s here } else { // can't use s here }
下面的代碼也是正確的:
if (obj instanceof String s && s.length() > 5) {.. s.contains(..) ..}
JEP 377: ZGC: A Scalable Low-Latency Garbage Collector (Production)
ZGC 已經在 JEP 333時集成到了 JDK 11 中,當時是做爲實驗特性引入的。在 JDK 11 發佈以來,咱們收到了不少積極的反饋,並修復了許多 bug,添加了不少新功能。更重要的是,ZGC 已經支持全部主流平臺:
如今能夠經過 -XX:+UnlockExperimentalVMOptions -XX:+UseZGC
命令選項啓用 ZGC。
Java語言增長文本塊功能。文本塊是多行字符串文字,能避免大多數狀況下的轉義問題。
在Java中,HTML, XML, SQL, JSON等字符串對象都很難閱讀和維護。
使用one-dimensional
的字符串語法:
String html = "<html>\n" + " <body>\n" + " <p>Hello, world</p>\n" + " </body>\n" + "</html>\n";
使用two-dimensional
文本塊語法:
String html = """ <html> <body> <p>Hello, world</p> </body> </html> """;
使用one-dimensional
的字符串語法:
String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" + "WHERE `CITY` = 'INDIANAPOLIS'\n" + "ORDER BY `EMP_ID`, `LAST_NAME`;\n";
使用two-dimensional
文本塊語法:
String query = """ SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB` WHERE `CITY` = 'INDIANAPOLIS' ORDER BY `EMP_ID`, `LAST_NAME`; """;
使用one-dimensional
的字符串語法:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js"); Object obj = engine.eval("function hello() {\n" + " print('\"Hello, world\"');\n" + "}\n" + "\n" + "hello();\n");
使用two-dimensional
文本塊語法:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js"); Object obj = engine.eval(""" function hello() { print('"Hello, world"'); } hello(); """);
文本塊是Java語言的新語法,能夠用來表示任何字符串,具備更高的表達能力和更少的複雜度。
文本塊的開頭定界符是由三個雙引號字符(""")組成的序列,後面跟0個或多個空格,最後跟一個行終止符。內容從開頭定界符的行終止符以後的第一個字符開始。
結束定界符是三個雙引號字符的序列。內容在結束定界符的第一個雙引號以前的最後一個字符處結束。
與字符串文字中的字符不一樣,文本塊的內容中能夠直接包含雙引號字符。容許在文本塊中使用\「,但不是必需的或不建議使用。
與字符串文字中的字符不一樣,內容能夠直接包含行終止符。容許在文本塊中使用\n,但不是必需或不建議使用。例如,文本塊:
""" line 1 line 2 line 3 """
等效於字符串文字:
"line 1\nline 2\nline 3\n"
或字符串文字的串聯:
"line 1\n" + "line 2\n" + "line 3\n"
JEP 379: Shenandoah: A Low-Pause-Time Garbage Collector (Production)
Shenandoah GC 由JEP 189 集成到 JDK 12 中。如今,Shenandoah GC 已經能夠用於生產環境了!(Shenandoah GC 的具體特性之後會有專門的文章講解,本篇文章略過)。
JEP 381: Remove the Solaris and SPARC Ports
刪除了對 Solaris/SPARC、Solaris/x64和 Linux/SPARC 端口支持的源代碼,並從新構建 JDK。這些代碼在 JDK 14中已經被標記爲廢棄的,並明確表示在將來版本中會刪除。
JEP 383: Foreign-Memory Access API (Second Incubator)
引入新的能使 Java 程序安全高效訪問 Java 堆內存以外的外部內存的 API。
JEP 384: Records (Second Preview)
經過 Records
(不知道如何翻譯,囧……)加強Java編程語言。Records提供了一種緊湊的語法來聲明類,這些類是淺層不可變數據的透明持有者。
咱們常常聽到這樣的抱怨:「Java太冗長」、「Java規則過多」。首當其衝的就是充當簡單集合的「數據載體」的類。爲了寫一個數據類,開發人員必須編寫許多低價值、重複且容易出錯的代碼:構造函數、訪問器、equals()、hashCode()和toString()等等。
儘管IDE能夠幫助開發人員編寫數據載體類的絕大多數編碼,可是這些代碼仍然冗長。
從表面上看,將Records是爲了簡化模板編碼而生的,可是它還有「遠大」的目標:modeling data as data
。records應該更簡單、簡潔、數據不可變。
records是Java的一種新的類型。同枚舉同樣,records也是對類的一種限制。records放棄了類一般享有的特性:將API和表示解耦。可是做爲回報,records使數據類變得很是簡潔。
一個record具備名稱和狀態描述。狀態描述聲明瞭record的組成部分。例如:
record Point(int x, int y) { }
由於records在語義上是數據的簡單透明持有者,因此記錄會自動獲取不少標準成員:
records不能擴展任何類,而且不能聲明私有字段之外的實例字段。聲明的任何其餘字段都必須是靜態的。
records類都是隱含的final類,而且不能是抽象類。這些限制使得records的API僅由其狀態描述定義,而且之後不能被其餘類實現或繼承。
也能夠顯式聲明從狀態描述自動派生的任何成員。能夠在沒有正式參數列表的狀況下聲明構造函數(這種狀況下,假定與狀態描述相同),而且在正常構造函數主體正常完成時調用隱式初始化(this.x=x)。這樣就能夠在顯式構造函數中僅執行其參數的驗證等邏輯,並省略字段的初始化,例如:
record Range(int lo, int hi) { public Range { if (lo > hi) /* referring here to the implicit constructor parameters */ throw new IllegalArgumentException(String.format("(%d,%d)", lo, hi)); } }
RecordDeclaration: {ClassModifier} record TypeIdentifier [TypeParameters] (RecordComponents) [SuperInterfaces] [RecordBody] RecordComponents: {RecordComponent {, RecordComponent}} RecordComponent: {Annotation} UnannType Identifier RecordBody: { {RecordBodyDeclaration} } RecordBodyDeclaration: ClassBodyDeclaration RecordConstructorDeclaration RecordConstructorDeclaration: {Annotation} {ConstructorModifier} [TypeParameters] SimpleTypeName [Throws] ConstructorBody
下面的方法會被加到java.lang.Class
中:
JEP 385: Deprecate RMI Activation for Removal
將 RMI Activation
機制標記爲廢棄,以便在未來的某個版本刪除掉。RMI Activation 是 RMI 的過期部分,可是這並不表示會棄用 RMI 的其餘部分。
以上就是 JDK 15
的所有新特性,咱們能夠看到 G1 GC 已經退出歷史舞臺,新的 ZGC
、Shenandoah GC
已經登上歷史舞臺。同時也丟棄了像自旋鎖
這種歷史包袱,增長了許多諸如文本塊
等簡潔的語法特性。咱們能夠預見 Java 的性能會愈來愈好,同時也會愈來愈簡潔。(固然簡潔程度跟 Kotlin 這種新興語言是比不了的,畢竟徹底沒有歷史包袱)。歡迎你們關注個人公衆號。
coding 筆記、點滴記錄,之後的文章也會同步到公衆號(Coding Insight)中,但願你們關注^_^
代碼和思惟導圖在 GitHub 項目中,歡迎你們 star!