官方文檔鏈接:https://openjdk.org/projects/jdk/21/
下載鏈接:https://www.oracle.com/cn/java/technologies/downloads/#jdk21-windows
1、介紹
JDK21 是2023.09.19發(fā)布的正式版
其他版本的含義:
- Alpha:軟件或系統(tǒng)的內(nèi)部測試版本,僅內(nèi)部人員使用。一般不向外部發(fā)布,通常會有很多 Bug,除非你也是測試人員,否則不建議使用,alpha 就是 α,是希臘字母的第一位,表示最初級的版本,beta 就是 β,alpha 版就是比 beta 還早的測試版,一般都是內(nèi)部測試的版本。
- Beta:公開測試版。β 是希臘字母的第二個,顧名思義,這一版本通常是在 Alpha 版本后,該版本相對于 Alpha 版已有了很大的改進,消除了嚴重的錯誤,但還是存在著一缺陷,需要經(jīng)過多次測試來進一步消除。這個階段的版本會一直加入新的功能。
- Gamma: 軟件或系統(tǒng)接近于成熟的版本,只需要做一些小的改進就能發(fā)行。是 beta 版做過一些修改,成為正式發(fā)布的候選版本。
- RC:Release Candidate,發(fā)行候選版本。和 Beta 版最大的差別在于 Beta 階段會一直加入新的功能,但是到了 RC 版本,幾乎就不會加入新的功能了,而主要著重于除錯。RC 版本是最終發(fā)放給用戶的最接近正式版的版本,發(fā)行后改正 bug 就是正式版了,就是正式版之前的最后一個測試版。
- GA:General Available,正式發(fā)布的版本,這個版本就是正式的版本。在國外都是用 GA 來說明 release 版本的。比如:MySQL Community Server 5.7.21 GA 這是 MySQL Community Server 5.7 第 21 個發(fā)行穩(wěn)定的版本,GA 意味著 General Available,也就是官方開始推薦廣泛使用了。
- Release:這個版本通常就是所謂的“最終版本”,在前面版本的一系列測試版之后,終歸會有一個正式版本,是最終交付用戶使用的一個版本,該版本有時也稱為標準版。一般情況下,Release 不會以單詞形式出現(xiàn)在軟件封面上,取而代之的是符號?。
- Stable:穩(wěn)定版。在開源軟件中,都有 stable 版,這個就是開源軟件的最終發(fā)行版,用戶可以放心大膽的用了。這一版本基于 Beta 版,已知 Bug 都被修復(fù),一般情況下,更新比較慢。
2、新功能
根據(jù)官方文檔:https://www.infoq.com/news/2023/09/java-21-so-far/
最終的 15 個新功能集(以JEP的形式)可分為四 (4) 類:核心 Java 庫、Java 語言規(guī)范、熱點和安全庫,根據(jù)官方文檔,分為了正式版和預(yù)覽版,思維導(dǎo)圖如下:
正式功能:
- 虛擬線程
- 序列集合
- 棄用 Windows 32 位 x86 移植
- 準備禁止動態(tài)加載代理
- 分代 ZGC
- switch 模式匹配
- 記錄模式
- 密鑰封裝機制 API
預(yù)覽版功能:
- 字符串模板(預(yù)覽)
- 外部函數(shù)和內(nèi)存 API(第三次預(yù)覽)
- 未命名模式和變量(預(yù)覽)
- 未命名類和實例主方法(預(yù)覽)
3、虛擬線程
你發(fā)任你發(fā),我用JAVA8
提供了一種更高效、更輕量級的線程模型
1、為什么需要加入虛擬線程
在此之前,我們創(chuàng)建線程后需要銷毀線程來釋放內(nèi)存,會造成大量的成本消耗,完美的解決方案就是我們用線程池,通過線程池來管理線程,并且共享線程相當于說我用的時候去租用一個線程。
這樣就解決了創(chuàng)建和銷毀的成本,但是呢,還有并發(fā)量沒有解決,線程逐漸增多之后,線程之間會存在頻繁切換,切換的成本很高
so 就引入了虛擬線程,使用虛擬線程進行切換,這樣成本就相當于只有一個線程在工作
2、使用
代碼層面兼容性很好,基本和原來的線程池沒有區(qū)別
首先創(chuàng)建一個普通線程,實現(xiàn)Runnable接口
public class ThreadDemo implements Runnable{
@Override
public void run() {
System.out.println("線程名為:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
1、通過Thread直接使用
Thread thread = Thread.startVirtualThread(new ThreadDemo());
2、使用ofVirtual(),構(gòu)建器模式啟動虛擬線程,您可以設(shè)置線程名稱、優(yōu)先級、異常處理和其他配置
Thread thread = Thread.ofVirtual().name("javaxiaobear").unstarted(new ThreadDemo());
3、通過Executors調(diào)用
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return i;
});
});
} // executor.close() is called implicitly, and waits
//另一種寫法
ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor();
Future<?> submit = executorService.submit(new ThreadDemo());
Object javaxiaobear = submit.get();
4、使用工廠模式創(chuàng)建虛擬線程,其實跟ofVirtual差不多
ThreadFactory factory = Thread.ofVirtual().factory();
Thread thread = factory.newThread(new ThreadDemo());
thread.setName("javaxiaobear");
thread.start();
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return i;
});
});
} // executor.close() is called implicitly, and waits
4、序列集合
官方文檔:https://openjdk.org/jeps/431
Java 的集合框架缺少表示具有定義的遇到順序的元素序列的集合類型,比如LinkedHashSet獲取最后一個元素,就需要遍歷整個集合,所以官方就增加了3個接口
有序集合是其
Collection
元素具有定義的遇到順序的集合,有序集合具有第一個和最后一個元素,它們之間的元素具有后繼和前驅(qū)。排序集合支持兩端的通用操作,并且支持從第一個到最后一個以及從最后一個到第一個(即正向和反向)處理元素。
1、有序集合
interface SequencedCollection<E> extends Collection<E> {
// new method
SequencedCollection<E> reversed();
// methods promoted from Deque
void addFirst(E);
void addLast(E);
E getFirst();
E getLast();
E removeFirst();
E removeLast();
}
2、序列集
interface SequencedSet<E> extends Set<E>, SequencedCollection<E> {
SequencedSet<E> reversed(); // covariant override
}
3、序列Map
interface SequencedMap<K,V> extends Map<K,V> {
// new methods
SequencedMap<K,V> reversed();
SequencedSet<K> sequencedKeySet();
SequencedCollection<V> sequencedValues();
SequencedSet<Entry<K,V>> sequencedEntrySet();
V putFirst(K, V);
V putLast(K, V);
// methods promoted from NavigableMap
Entry<K, V> firstEntry();
Entry<K, V> lastEntry();
Entry<K, V> pollFirstEntry();
Entry<K, V> pollLastEntry();
}
5、棄用 Windows 32 位 x86 移植
這里就很簡單,未來將不支持32位的系統(tǒng)了
6、準備禁止動態(tài)加載代理
當代理動態(tài)加載到正在運行的 JVM 中時發(fā)出警告。這些警告旨在幫助用戶為將來的版本做好準備,該版本默認情況下不允許動態(tài)加載代理,以提高默認情況下的完整性。在啟動時加載代理的可服務(wù)性工具不會導(dǎo)致在任何版本中發(fā)出警告.
總的來說就是在JVM中禁止動態(tài)加載代理
在 JDK 21 中,允許動態(tài)加載代理,但 JVM 在發(fā)生這種情況時會發(fā)出警告。例如:
WARNING: A {Java,JVM TI} agent has been loaded dynamically (file:/u/bob/agent.jar)
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
WARNING: Dynamic loading of agents will be disallowed by default in a future release
要允許工具動態(tài)加載代理而不發(fā)出警告,用戶必須-XX:+EnableDynamicAgentLoading
在命令行上使用該選項運行。
7、分代 ZGC
ZGC(JEP 333)專為低延遲和高可擴展性而設(shè)計,通過擴展 Z 垃圾收集器 ( ZGC ) 來維護年輕對象和老對象的不同代,從而提高應(yīng)用程序性能。這將使 ZGC 能夠更頻繁地收集年輕對象(這些對象往往會在年輕時死亡)
在 Java 21 中,我們可以這樣開啟分代 ZGC:
java -XX:+UseZGC -XX:+ZGenerational ...
同時,分代 ZGC 中不再需要設(shè)置年輕代大小、年輕代進入老年代所需要的 GC 次數(shù)、GC 線程數(shù)等,ZGC 將這些全部動態(tài)化,并在內(nèi)部自動調(diào)優(yōu)?,F(xiàn)在只需要設(shè)置一個參數(shù),即最大內(nèi)存大小 -Xmx
。
具體詳情大家可參考這篇:https://sdl.moe/post/generational-zgc/
8、switch 模式匹配
官方文檔:https://openjdk.org/jeps/441
switch
通過表達式和語句的模式匹配增強 Java 編程語言。擴展模式匹配switch
允許針對多個模式測試表達式,每個模式都有一個特定的操作,以便可以簡潔、安全地表達復(fù)雜的面向數(shù)據(jù)的查詢,實際上就是一個語法升級,代碼美觀了
1、使用
public class SwitchTest {
public static void main(String[] args) {
int i = 88;
System.out.println("以前寫法"+ formatter(i));
System.out.println(formatterPatternSwitch(i));
}
/**
* 以前寫法
* @param obj
* @return
*/
public static String formatter(Object obj) {
String formatted = "unknown";
if (obj instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (obj instanceof Long l) {
formatted = String.format("long %d", l);
} else if (obj instanceof Double d) {
formatted = String.format("double %f", d);
} else if (obj instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
/**
* 現(xiàn)在寫法
* @param obj
* @return
*/
public static String formatterPatternSwitch(Object obj) {
return switch (obj) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> obj.toString();
};
}
}
2、空值處理
/**
* 之前寫法
* @param s
*/
public static void testFooBarOld(String s) {
if (s == null) {
System.out.println("是空值!");
return;
}
switch (s) {
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("javaxiaobear is Good");
}
}
/**
* 新特性寫法
* @param s
*/
static void testFooBarNew(String s) {
switch (s) {
case null -> System.out.println("Oops");
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("javaxiaobear is Good");
}
}
9、記錄模式
官方文檔:https://openjdk.org/jeps/440
Record Patterns的實現(xiàn)原理主要涉及兩個方面:
- 記錄類型
- 記錄類型是一種新的類聲明形式,通過record關(guān)鍵字來定義。
模式匹配
模式匹配是指根據(jù)給定的模式來匹配某個對象,并執(zhí)行相應(yīng)的操作。在Record Patterns中,我們可以使用instance of關(guān)鍵字和模式變量
來進行模式匹配。具體地說,當我們使用Record Patterns進行模式匹配時,編譯器會自動為記錄類型生成一個模式匹配方法。這個方法
接受一個對象作為參數(shù)蘭擔據(jù)給定的模式進行匹配。如果匹配成功,則將字段值綁定到相應(yīng)的模式變量中,從而可以在后續(xù)代碼中用。
10、密鑰封裝機制 API
引入密鑰封裝機制 (KEM) 的 API,這是一種使用公鑰加密來保護對稱密鑰的加密技術(shù)。密鑰封裝是一種現(xiàn)代加密技術(shù),它使用非對稱或公鑰加密來保護對稱密鑰。這樣做的傳統(tǒng)技術(shù)是使用公鑰加密隨機生成的對稱密鑰,但這需要填充并且很難證明安全。相反,密鑰封裝機制 (KEM) 使用公鑰的屬性來派生相關(guān)的對稱密鑰,這不需要填充。文章來源:http://www.zghlxwxcb.cn/news/detail-737521.html
KEM 由三個功能組成:文章來源地址http://www.zghlxwxcb.cn/news/detail-737521.html
- 密鑰對生成函數(shù),返回包含公鑰和私鑰的密鑰對。
- 密鑰封裝函數(shù),由發(fā)送方調(diào)用,采用接收方的公鑰和加密選項;它返回一個秘密密鑰K 和一個密鑰封裝消息(在 ISO 18033-2 中稱為*密文)。*發(fā)送方將密鑰封裝消息發(fā)送給接收方。
- 密鑰解封裝函數(shù),由接收方調(diào)用,獲取接收方的私鑰和接收到的密鑰封裝消息;它返回密鑰K。
import javax.crypto.KEM;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
public class KEMTest {
public static void main(String[] args) throws NoSuchAlgorithmException {
//RSA算法
KeyPairGenerator instance = KeyPairGenerator.getInstance("RSA");
//初始化秘鑰大小
instance.initialize(1024);
//生成密鑰對
KeyPair kp = instance.generateKeyPair();
//獲取公鑰
System.out.println(kp.getPublic());
//獲取私鑰
System.out.println(kp.getPrivate());
}
}
到了這里,關(guān)于JDK 新特性深度分析,但我用Java 8的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!