JDK 15已經于2020年9月15日如期釋出。本文介紹JDK 15新特性。
釋出版本說明
根據釋出的規劃,這次釋出的 JDK 15 将是一個短期的過度版,隻會被 Oracle 支援(維護)6 個月,直到明年 3 月的 JDK 16 釋出此版本将停止維護。而 Oracle 下一個長期支援版(LTS 版)會在明年的 9 月份候釋出(Java 17),LTS 版每 3 年釋出一個,上一次長期支援版是 18 年 9 月釋出的 JDK 11。 下圖展示了各個版本的釋出曆史。
安裝包下載下傳
主要分為OpenJDK版本和Oracle版本,下載下傳位址如下:
- OpenJDK版本: https://jdk.java.net/15/
- Oracle版本: http://www.oracle.com/technetwork/java/javase/downloads/index.html
上述版本,如果是個人學習用途,則差異不大。但如果是用于商業用途,則需要仔細看好相關的授權。Oracle JDK根據二進制代碼許可協定獲得許可,而OpenJDK根據GPL v2許可獲得許可。
安裝、驗證
本例子以OpenJDK版本為例。解壓安裝包
openjdk-15_windows-x64_bin.zip
到任意位置。
設定系統環境變量“JAVA_HOME”,如下圖所示。
在使用者變量“Path”中,增加“%JAVA_HOME%bin”。
安裝完成後,執行下面指令進行驗證:
>java -version
openjdk version "15" 2020-09-15
OpenJDK Runtime Environment (build 15+36-1562)
OpenJDK 64-Bit Server VM (build 15+36-1562, mixed mode, sharing)
更多有關Java的基本知識,可以參閱《
Java核心程式設計》這本書,描述的非常詳細。
JDK 15 新特性說明
JDK 15 為使用者提供了14項主要的增強/更改,包括一個孵化器子產品,三個預覽功能,兩個不推薦使用的功能以及兩個删除功能。
1. EdDSA 數字簽名算法
新加入 Edwards-Curve 數字簽名算法(EdDSA)實作加密簽名。在許多其它加密庫(如 OpenSSL 和 BoringSSL)中得到支援。與 JDK 中的現有簽名方案相比,EdDSA 具有更高的安全性和性能。這是一個新的功能。
使用示例如下:
// example: generate a key pair and sign
KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
KeyPair kp = kpg.generateKeyPair();
// algorithm is pure Ed25519
Signature sig = Signature.getInstance("Ed25519");
sig.initSign(kp.getPrivate());
sig.update(msg);
byte[] s = sig.sign();
// example: use KeyFactory to contruct a public key
KeyFactory kf = KeyFactory.getInstance("EdDSA");
boolean xOdd = ...
BigInteger y = ...
NamedParameterSpec paramSpec = new NamedParameterSpec("Ed25519");
EdECPublicKeySpec pubSpec = new EdECPublicKeySpec(paramSpec, new EdPoint(xOdd, y));
PublicKey pubKey = kf.generatePublic(pubSpec);
有關EdDSA 數字簽名算法的詳細内容見
RFC 8032規範。
2. 封閉類(預覽特性)
可以是封閉類和或者封閉接口,用來增強 Java 程式設計語言,防止其他類或接口擴充或實作它們。
有了這個特性,意味着以後不是你想繼承就繼承,想實作就實作了,你得經過允許才行。
示例如下:
public abstract sealed class Student
permits ZhangSan, LiSi, ZhaoLiu {
...
}
類 Student 被 sealed 修飾,說明它是一個封閉類,并且隻允許指定的 3 個子類繼承。
3. 隐藏類
此功能可幫助需要在運作時生成類的架構。架構生成類需要動态擴充其行為,但是又希望限制對這些類的通路。隐藏類很有用,因為它們隻能通過反射通路,而不能從普通位元組碼通路。此外,隐藏類可以獨立于其他類加載,這可以減少架構的記憶體占用。這是一個新的功能。
4. 移除了 Nashorn JavaScript 腳本引擎
移除了 Nashorn JavaScript 腳本引擎、APIs,以及 jjs 工具。這些早在 JDK 11 中就已經被标記為 deprecated 了,JDK 15 被移除就很正常了。
Nashorn 是 JDK 1.8 引入的一個 JavaScript 腳本引擎,用來取代 Rhino 腳本引擎。Nashorn 是 ECMAScript-262 5.1 的完整實作,增強了 Java 和 JavaScript 的相容性,并且大大提升了性能。
那麼為什麼要移除?
官方的解釋是主要的:随着 ECMAScript 腳本語言的結構、API 的改編速度越來越快,維護 Nashorn 太有挑戰性了,是以……。
5. 重新實作 DatagramSocket API
重新實作舊版 DatagramSocket API,更簡單、更現代的實作來代替java.net.DatagramSocket和java.net.MulticastSocketAPI 的基礎實作,提高了 JDK 的可維護性和穩定性。
新的底層實作将很容易使用虛拟線程,目前正在 Loom 項目中進行探索。這也是 JEP 353 的後續更新版本,JEP 353 已經重新實作了 Socket API。
6. 準備禁用和廢除偏向鎖
在 JDK 15 中,預設情況下禁用偏向鎖(Biased Locking),并棄用所有相關的指令行選項。
後面再确定是否需要繼續支援偏向鎖,國為維護這種鎖同步優化的成本太高了。
7. 模式比對(第二次預覽)
第一次預覽是 JDK 14 中提出來的,點選
這裡檢視我之前寫的詳細教程。
Java 14 之前用法:
if (obj instanceof String) {
String s = (String) obj;
// 使用s
}
Java 14之後的用法:
if (obj instanceof String s) {
// 使用s
}
Java 15 并沒有對此特性進行調整,繼續預覽特性,隻是為了收集更多的使用者回報,可能還不成熟吧。
8. ZGC 功能轉正
ZGC是一個可伸縮、低延遲的垃圾回收器。
ZGC 已由JEP 333內建到JDK 11 中,其目标是通過減少 GC 停頓時間來提高性能。借助 JEP 377,JDK 15 将 ZGC 垃圾收集器從預覽特性變更為正式特性而已,沒錯,轉正了。
這個 JEP 不會更改預設的 GC,預設仍然是 G1。
9. 文本塊功能轉正
文本塊,是一個多行字元串,它可以避免使用大多數轉義符号,自動以可預測的方式格式化字元串,并讓開發人員在需要時可以控制格式。
文本塊最早準備在 JDK 12 添加的,但最終撤消了,然後在 JDK 13 中作為預覽特性進行了添加,然後又在 JDK 14 中再次預覽,在 JDK 15 中,文本塊終于轉正,暫不再做進一步的更改。
Java 13 之前用法,使用one-dimensional的字元串文法:
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
Java 13 之後用法,使用two-dimensional文本塊文法:
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
10. Shenandoah 垃圾回收算法轉正
Shenandoah 垃圾回收從實驗特性變為産品特性。這是一個從 JDK 12 引入的回收算法,該算法通過與正在運作的 Java 線程同時進行疏散工作來減少 GC 暫停時間。Shenandoah 的暫停時間與堆大小無關,無論堆棧是 200 MB 還是 200 GB,都具有相同的一緻暫停時間。
JDK 15 Shenandoah垃圾收集器從預覽特性變更為正式特性而已,沒錯,又是轉正了。
11. 移除了 Solaris 和 SPARC 端口。
移除了 Solaris/SPARC、Solaris/x64 和 Linux/SPARC 端口的源代碼及建構支援。這些端口在 JDK 14 中就已經被标記為 deprecated 了,JDK 15 被移除也不奇怪。
12. 外部存儲器通路 API(二次孵化)
這個最早在 JDK 14 中成為孵化特性,JDK 15 繼續二次孵化并對其 API 有了一些更新。
目的是引入一個 API,以允許 Java 程式安全有效地通路 Java 堆之外的外部記憶體。這同樣是 Java 14 的一個預覽特性。
13. Records Class(二次預覽)
Records Class 也是第二次出現的預覽功能,它在 JDK 14 中也出現過一次了,使用 Record 可以更友善的建立一個常量類,使用的前後代碼對比如下。
舊寫法:
class Point {
private final int x;
private final int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
int x() { return x; }
int y() { return y; }
public boolean equals(Object o) {
if (!(o instanceof Point)) return false;
Point other = (Point) o;
return other.x == x && other.y = y;
}
public int hashCode() {
return Objects.hash(x, y);
}
public String toString() {
return String.format("Point[x=%d, y=%d]", x, y);
}
}
新寫法:
record Point(int x, int y) { }
也就是說在使用了 record 之後,就可以用一行代碼編寫出一個常量類,并且這個常量類還包含了構造方法、toString()、equals() 和 hashCode() 等方法。
14. 廢除 RMI 激活
廢除 RMI 激活,以便在将來進行删除。需要說明的是,RMI 激活是 RMI 中一個過時的元件,自 Java 8 以來一直是可選的。