一、為什么要了解JDK15?
2020年9月15日,Oracle官方發布了JDK15版本,及時關注官方的更新動態,可以讓我們在日常開發中更合理的選擇更加優秀的工具方法,避免使用一些過時的或一些即將被刪除類和方法,保障程序的健壯性、穩定性、可移植性。
二、JDK15都為我們帶來了哪些東西?
- JEP 339: Edwards-Curve 數字簽名算法(EdDSA)
- JEP 360: 密封類(預覽)
- JEP 371: 隱藏類
- JEP 372: 刪除Nashorn JavaScript引擎
- JEP 373: 重新實現舊版DatagramSocket API
- JEP 374: 禁用和棄用偏置鎖定
- JEP 375: instanceof的模式匹配(第二預覽)
- JEP 377: ZGC:可擴展的低延遲垃圾收集器
- JEP 378: 文字塊
- JEP 379: Shenandoah:低暫停時間的垃圾收集器
- JEP 381: 刪除Solaris和SPARC端口
- JEP 383: 外部存儲器訪問API(第二個孵化器)
- JEP 384: Records(第二預覽)
- JEP 385: 棄用RMI激活以進行刪除
JEP:JDK Enhancement Proposals ,JDK 特性的新增和修改建議。
三、具體說一說JDK15的特性。
1. JEP 339: Edwards-Curve 數字簽名算法(EdDSA)
官方描述:
EdDSA是一種現代的橢圓曲線簽名方案,與JDK中的現有簽名方案相比,具有多個優點。
- 在相同的安全強度下,開發比現有的ECDSA實現(使用本機C代碼)更好的性能的EdDSA平台無關的實現。例如,在安全性〜126位時使用Curve25519的EdDSA應該與在安全性〜128位時使用曲線secp256r1的ECDSA一樣快。
- 假設平台在恆定時間內執行64位整數加/乘,請確保時序與秘密無關。另外,該實現將不會基於秘密分支。這些屬性對於防止側通道攻擊非常有用。
簡而言之:
Edwards-Curve 數字簽名算法(EdDSA)實現加密簽名功能。且比現有的JDK 中的簽名安全性和性能更高。
2. JEP 360: 密封類(預覽)
官方描述:
通過密封的類和接口增強Java編程語言。密封的類和接口限制可以擴展或實現它們的其他類或接口。通過將sealed修飾符應用於其聲明來密封類。然后,在anyextends和implements子句之后,該permits子句指定允許擴展密封類的類。
簡而言之:
限定接口的實現或子類,不是所有的類都能繼承此類或實現此類。
注意:
- sealed:隱含子類 permits : 許可證
- non-sealed:隱含非受限子類
- final:隱含無子類
- 每個允許的子類都只能使用修飾符 final ,sealed和non-sealed中的一個,且三者互斥。
代碼實現:
1 // 創建Person 密封類 2 public abstract sealed class Person permits Student, Teacher, Doctor{ 3 4 } 5 6 // 學生類繼承人類 7 non-sealed class Student extends Person{ } 8 9 // 老師類繼承人類 10 final class Teacher extends Person{ } 11 12 // 醫生類繼承人類 13 sealed class Doctor extends Person permits OutpDoctor, InpatDoctor{ } 14 15 // 門診醫生繼承人類 16 final class OutpDoctor extends Doctor{ } 17 18 // 住院醫生繼承人類 19 non-sealed class InpatDoctor extends Doctor{ }
1 // 方法類型描述 2 public sealed interface MethodTypeDesc permits DynamicConstantDesc, MethodTypeDescImpl {} 3 4 // 方法類型描述實現 5 final class MethodTypeDescImpl implements MethodTypeDesc { } 6 7 // 動態約束描述 8 non-sealed class DynamicConstantDesc implements MethodTypeDesc {}
3. JEP 371: 隱藏類
官方描述:
隱藏類是其他類的字節碼不能直接使用的類。隱藏類適用於在運行時生成類並通過反射間接使用它們的框架。隱藏類可以定義為訪問控制嵌套的成員,並且可以獨立於其他類進行卸載。
簡而言之:
隱藏類的超類型是由類加載器創建的,但隱藏類本身的創建並不涉及任何類加載器。所以可以方便的進行卸載且不用考慮安全問題,並且可以減少程序的內存占用。
4. JEP 372: 刪除Nashorn JavaScript引擎
官方描述:
隨着ECMAScript語言構造以及API的快速適應和修改,我們發現Nashorn難以維護。官方決定刪除Nashorn JavaScript腳本引擎和API,以及該jjs
工具。
兩個JDK模塊將被永久刪除:
- jdk.scripting.nashorn-包含jdk.nashorn.api.scripting和 jdk.nashorn.api.tree軟件包。
- jdk.scripting.nashorn.shell-包含jjs工具。
5. JEP 373: 重新實現舊版DatagramSocket API(套接字)
官方描述:
用更易於維護和調試的更簡單,更現代的實現來替換java.net.DatagramSocket
和java.net.MulticastSocket
API的基礎實現。新的實現將很容易適應虛擬線程的工作,當前正在Project Loom中進行探索。
改動原因:
java.net.DatagramSocket
和java.net.MulticastSocket
API的代碼庫及其基礎實現很舊且脆弱:
-
實現可以追溯到JDK 1.0。它們是傳統Java和C代碼的混合,難以維護和調試。
-
的實現
MulticastSocket
尤其成問題,因為它可以追溯到IPv6仍處於開發階段。許多基本的本機實現都嘗試以難以維護的方式協調IPv4和IPv6。 -
該實現還存在一些並發問題(例如,異步關閉),需要進行大修才能正確解決。
此外,在駐留而不是阻塞系統調用中底層內核線程的虛擬線程的情況下,當前實現不適合此目的。隨着基於數據報的傳輸再次獲得牽引力(例如 QUIC),需要更簡單,更可維護的實現。
6.JEP 374: 禁用和棄用偏置鎖定
官方描述:
在JDK 15之前,始終啟用並提供偏置鎖定。使用此JEP,除非 -XX:+UseBiasedLocking
在命令行上設置,否則在啟動HotSpot時將不再啟用偏置鎖定。
改動原因:
確定是否需要繼續支持偏向鎖定的傳統同步優化,這是維護成本很高的方法。有偏見的鎖定會帶來爭用時需要進行昂貴的撤銷操作的代價。
7.JEP 375: instanceof的模式匹配(第二預覽)
官方描述:
通過為操作員提供模式匹配來增強Java編程語言instanceof。模式匹配使程序中的通用邏輯(即從對象中有條件地提取組件)得以更簡潔,更安全地表示。
簡而言之:
可以使我們的代碼更加簡潔。
代碼示例:
1 public static void main(String[] args) { 2 Object str = "模式匹配"; 3 // 模式匹配 4 // 綁定變量s的作用域在&&運算符的右側以及true塊中、綁定變量s不在||右側的范圍內 5 // if(str instanceof String s && s.length() > 0 ){ 6 if(str instanceof String s){ 7 System.out.println(s); 8 }else { 9 // s不能作用於此處 10 // System.out.printf(s); 11 } 12 }
8. JEP 377: ZGC:可擴展的低延遲垃圾收集器(轉正)
官方描述:
對ZGC的測試表明它是穩定的,並且在撰寫本文時,我們已經有幾個月沒有收到針對ZGC的新錯誤了。借助ZGC如今擁有的穩定性,功能集和平台支持,是時候刪除其實驗狀態並使其成為產品功能了。
今天,可以通過-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
命令行選項啟用ZGC 。使ZGC成為產品(非實驗性)功能意味着-XX:+UnlockExperimentalVMOptions
不再需要該選件。
該JEP不建議更改默認GC,該默認GC仍為G1。
簡而言之:
ZGC垃圾收集器在JDK15成為正式版,我們可以通過-XX:+UseZGC
命令行選項啟用ZGC,但是需要注意的是默認的垃圾收集器仍然是G1。
9. JEP 378: 文字塊(轉正)
官方描述:
將文本塊添加到Java語言。文本塊是多行字符串文字,它避免了大多數轉義序列的需要,以一種可預測的方式自動設置字符串的格式,並在需要時使開發人員可以控制格式。
解決了在Java中,在字符串文字中嵌入HTML,XML,SQL或JSON片段"..."
通常需要先進行轉義和串聯的大量編輯,然后才能編譯包含該片段的代碼。該代碼段通常難以閱讀且難以維護的問題。
代碼示例:
1 public static void main(String[] args) { 2 String html = "<html>\n" + 3 " <body>\n" + 4 " <p>Hello, world</p>\n" + 5 " </body>\n" + 6 "</html>\n"; 7 8 String htmlText = """ 9 <html> 10 <body> 11 <p>Hello, world</p> 12 </body> 13 </html> 14 """; 15 16 System.out.println("html長度" + html.length()); 17 System.out.println("htmlText長度" + htmlText.length()); 18 19 String query = "SELECT \"EMP_ID\", \"LAST_NAME\" FROM \"EMPLOYEE_TB\"\n" + 20 "WHERE \"CITY\" = 'INDIANAPOLIS'\n" + 21 "ORDER BY \"EMP_ID\", \"LAST_NAME\";\n"; 22 23 String queryText = """ 24 SELECT "EMP_ID", "LAST_NAME" FROM "EMPLOYEE_TB" 25 WHERE "CITY" = 'INDIANAPOLIS' 26 ORDER BY "EMP_ID", "LAST_NAME"; 27 """; 28 29 System.out.println("query長度" + query.length()); 30 System.out.println("queryText長度" + queryText.length()); 31 32 // \:取消換行操作 33 // \s:標識一個空格 34 String sql1 = """ 35 SELECT id, name, age \ 36 FROM person\s\ 37 WHERE id > 4 \ 38 ORDER BY age DESC 39 """; 40 41 String sql2 = "SELECT id, name, age FROM person WHERE id > 4 ORDER BY age DESC"; 42 43 }
錯誤代碼示例:
1 String a = """"""; // no line terminator after opening delimiter 2 3 String b = """ """; // no line terminator after opening delimiter 4 5 String c = """ 6 "; // no closing delimiter (text block continues to EOF) 7 8 String d = """ 9 abc \ def 10 """; // unescaped backslash (see below for escape processing)
注意:
文本塊: """ line 1 line 2 line 3 """ 等效於字符串文字: "line 1\nline 2\nline 3\n" 或字符串文字的串聯: "line 1\n" + "line 2\n" + "line 3\n" --------------------------------------------------------- """ line 1 line 2 line 3""" 等效於字符串文字: "line 1\nline 2\nline 3"
10. JEP 379: Shenandoah:低暫停時間的垃圾收集器(轉正)
官方描述:
將Shenandoah垃圾收集器從實驗功能更改為產品功能。
在JDK 12和更高版本中,通過-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC
選項啟用了Shenandoah 。將Shenandoah成為產品功能意味着-XX:+UnlockExperimentalVMOptions
不再需要。
簡而言之:
Shenandoah垃圾收集器功能轉正,可以通過-XX:+UseShenandoahGC直接使用,Shenandoah 的暫停時間與堆大小無關。
11. JEP 381: 刪除Solaris和SPARC端口
官方描述:
刪除所有特定於Solaris操作系統的源代碼。
刪除所有特定於SPARC體系結構的源代碼。
更新文檔和源代碼注釋以用於將來的版本。
改動原因:
當前正在開發的許多項目和功能(例如Valhalla,Loom和Panama)都需要對CPU體系結構和特定於操作系統的代碼進行重大更改。放棄對Solaris和SPARC端口的支持將使OpenJDK社區中的貢獻者能夠加速新功能的開發,這些新功能將推動平台向前發展。
12.JEP 383: 外部存儲器訪問API(第二個孵化器)
官方描述:
引入一個API,以允許Java程序安全有效地訪問Java堆之外的外部內存。
在Java 14作為孵化API,在JDK15中第二次孵化。
以jdk.incubator.foreign
相同的名稱包形式提供了外部存儲器訪問API ;它引入了三個主要抽象:MemorySegment
,MemoryAddress
和MemoryLayout。
13.JEP 384: Records(第二預覽)
官方描述:
使用records增強Java編程語言,record 是充當不可變數據的透明載體的類。記錄可以看作是名義元組。
- 設計一個表達簡單值集合的面向對象的構造。
- 幫助程序員專注於對不可變數據進行建模,而不是對可擴展行為進行建模。
- 自動實現數據驅動的方法,例如
equals
和訪問器。 - 保留長期的Java原則,例如標稱類型和遷移兼容性
官方示例:
例如,先前聲明的記錄record Point(int x, int y) { }-將被編譯為: record Point(int x, int y) { // Implicitly declared fields private final int x; private final int y; // Other implicit declarations elided ... // Implicitly declared canonical constructor Point(int x, int y) { this.x = x; this.y = y; } }
簡而言之:
似於lombok,主要目的是為了簡化作用,不用再寫構造方法、equals,hashCode,toString等方法。
代碼示例:
1 public record Student(String name,int age) { 2 } 3 4 public class Main { 5 public static void main(String[] args) { 6 Student student = new Student("張三",20); 7 System.out.println(student); 8 System.out.println(student.name()); 9 System.out.println(student.age()); 10 } 11 }
14.JEP 385: 棄用RMI激活以進行刪除
官方描述:
棄用RMI激活 機制以便將來刪除。RMI激活是RMI的過時部分,自Java 8開始,RMI激活是可選的。不會棄用RMI的其他部分。
改動原因:
分布式系統至少在過去十年中一直基於Web技術。Web服務領域已經解決了有關穿越防火牆,篩選請求,身份驗證和安全性的問題。延遲實例化資源由負載平衡器,業務流程和容器處理。這些機制在分布式系統的RMI激活模型中均不存在。
RMI激活的使用量幾乎消失了。沒有證據表明有任何新的應用程序被編寫為使用RMI激活,並且有證據表明很少有現有應用程序使用RMI激活。對各種開放源代碼庫的搜索幾乎沒有發現任何與激活相關的API。
間而言之:
RMI激活的功能使用極少,Web服務有更優秀的問題解決方案,RMI激活增加了維護的費用。
四、總結
總的來說,JDK15新功能不多,可以根據自己的實際需要,根據JDK版本功能走向來選擇合理的功能。