一、為什麼要了解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版本功能走向來選擇合理的功能。