最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java?JDK21?新特性全面解析

 更新時間:2026年05月23日 14:07:18   作者:哎呦喂606  
JDK221作為JTS版本,核心正式特性提升開發(fā)效率、程序性能和代碼安全性,虛擬線線、模式匹配fswitch、記錄模式、密封類、分代ZGC、序列化集合六大特性,適合高并發(fā)、大數(shù)據(jù)、企業(yè)級應(yīng)用場景,本文給大家介紹Java?JDK21?新特性,感興趣的朋友跟隨小編一起看看吧

JDK21 是 Oracle 發(fā)布的繼 JDK8、JDK11、JDK17 之后的第四個長期支持版(LTS),于 2023 年 9 月 19 日正式發(fā)布,共包含 15 個新特性,涵蓋語言增強(qiáng)、性能優(yōu)化、API 擴(kuò)展等多個維度,極大提升了開發(fā)效率、程序性能和代碼安全性。

提示:本文所有代碼均基于 JDK21 環(huán)境編寫,運(yùn)行前請確保已安裝 JDK21 并配置好環(huán)境變量;涉及預(yù)覽特性的代碼,需在編譯和運(yùn)行時添加 --enable-preview 參數(shù)(具體用法見對應(yīng)特性說明)。

一、核心正式特性

1. 虛擬線程(Virtual Threads,JEP 444)—— 輕量級高并發(fā)利器

1.1 特性說明

虛擬線程是 JDK21 最受關(guān)注的核心特性,它是由 JVM 管理的輕量級線程,而非操作系統(tǒng)內(nèi)核線程,徹底解決了傳統(tǒng)平臺線程(Platform Thread)資源占用高、上下文切換開銷大的問題。虛擬線程的內(nèi)存占用極低(每個僅需幾 KB),可輕松創(chuàng)建數(shù)百萬個并發(fā)任務(wù),尤其適合 I/O 密集型場景(如接口調(diào)用、數(shù)據(jù)庫操作、文件讀寫等),能極大提升程序吞吐量,且無需修改現(xiàn)有線程相關(guān)代碼,上手成本極低。

核心優(yōu)勢:

  • 輕量級:內(nèi)存占用遠(yuǎn)低于平臺線程,單個 JVM 可創(chuàng)建數(shù)百萬個虛擬線程。
  • 低開銷:上下文切換由 JVM 管理,無需操作系統(tǒng)內(nèi)核參與,開銷極小。
  • 易遷移:現(xiàn)有基于 RunnableCallable 的代碼可直接遷移,無需修改業(yè)務(wù)邏輯。
  • 結(jié)構(gòu)化并發(fā):配合 Executors.newVirtualThreadPerTaskExecutor(),簡化并發(fā)任務(wù)管理。
  • 調(diào)度優(yōu)化:虛擬線程阻塞時會自動切換到其他正在運(yùn)行的線程,充分利用 CPU 時間,避免資源閑置。
  • 無規(guī)模限制:不受操作系統(tǒng)對線程數(shù)量的限制,理論上支持無限量創(chuàng)建(受限于內(nèi)存)。

1.2 代碼樣例(4種創(chuàng)建方式,推薦第三種)

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
 * 虛擬線程 4種創(chuàng)建方式演示
 */
  public static void main(String[] args) throws InterruptedException {
        // 方式1:通過 Thread.startVirtualThread() 直接創(chuàng)建(最簡單)
        Thread.startVirtualThread(() -> {
            System.out.println("方式1:虛擬線程運(yùn)行中,線程類型:" + Thread.currentThread().getClass().getSimpleName());
            try {
                // 模擬I/O操作(睡眠100ms)
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("方式1:虛擬線程執(zhí)行完畢");
        });
        // 方式2:通過 Thread.Builder 構(gòu)建(可設(shè)置線程名稱,移除不支持的優(yōu)先級)
        Thread virtualThread = Thread.ofVirtual()
                .name("virtual-thread-2") // 設(shè)置線程名稱(虛擬線程支持設(shè)置名稱)
                .unstarted(() -> {
                    System.out.println("方式2:虛擬線程運(yùn)行中,線程名稱:" + Thread.currentThread().getName());
                    try {
                        TimeUnit.MILLISECONDS.sleep(150);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println("方式2:虛擬線程執(zhí)行完畢");
                });
        virtualThread.start(); // 啟動虛擬線程
        // 方式3:通過線程池創(chuàng)建(推薦,適合批量管理并發(fā)任務(wù))
        // newVirtualThreadPerTaskExecutor():每個任務(wù)對應(yīng)一個虛擬線程
        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
            for (int i = 0; i < 5; i++) {
                int taskId = i;
                executor.submit(() -> {
                    System.out.println("方式3:虛擬線程任務(wù)" + taskId + "運(yùn)行中,線程ID:" + Thread.currentThread().threadId());
                    try {
                        TimeUnit.MILLISECONDS.sleep(200);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println("方式3:虛擬線程任務(wù)" + taskId + "執(zhí)行完畢");
                });
            }
        } // try-with-resources 自動關(guān)閉線程池,無需手動shutdown
        // 方式4:通過 ThreadFactory 創(chuàng)建(靈活定制線程屬性)
        // 替換 namePrefix 為 name(prefix, start),移除無效的 daemon 方法
        ThreadFactory factory = Thread.ofVirtual()
                .name("custom-virtual-thread-", 0) // 名稱前綴 + 起始數(shù)字(0開始)
                .factory();
        Thread customThread = factory.newThread(() -> {
            System.out.println("方式4:自定義虛擬線程運(yùn)行中,線程名稱:" + Thread.currentThread().getName());
            try {
                TimeUnit.MILLISECONDS.sleep(250);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("方式4:自定義虛擬線程執(zhí)行完畢");
        });
        customThread.start();
        // 等待所有虛擬線程執(zhí)行完畢(主線程阻塞,避免程序提前退出)
        TimeUnit.SECONDS.sleep(1);
        System.out.println("所有虛擬線程執(zhí)行完畢,主線程退出");
    }

1.3 運(yùn)行結(jié)果(關(guān)鍵信息)

方式1:虛擬線程運(yùn)行中,線程類型:VirtualThread
方式2:虛擬線程運(yùn)行中,線程名稱:virtual-thread-2
方式3:虛擬線程任務(wù)3運(yùn)行中,線程ID:40
方式3:虛擬線程任務(wù)2運(yùn)行中,線程ID:39
方式3:虛擬線程任務(wù)4運(yùn)行中,線程ID:41
方式3:虛擬線程任務(wù)0運(yùn)行中,線程ID:37
方式3:虛擬線程任務(wù)1運(yùn)行中,線程ID:38
方式1:虛擬線程執(zhí)行完畢
方式2:虛擬線程執(zhí)行完畢
方式3:虛擬線程任務(wù)0執(zhí)行完畢
方式3:虛擬線程任務(wù)2執(zhí)行完畢
方式3:虛擬線程任務(wù)4執(zhí)行完畢
方式3:虛擬線程任務(wù)3執(zhí)行完畢
方式3:虛擬線程任務(wù)1執(zhí)行完畢
方式4:自定義虛擬線程運(yùn)行中,線程名稱:custom-virtual-thread-0
方式4:自定義虛擬線程執(zhí)行完畢
所有虛擬線程執(zhí)行完畢,主線程退出

1.4 注意事項(xiàng)

  • 虛擬線程適合 I/O 密集型場景,不適合 CPU 密集型場景(CPU 密集型任務(wù)建議使用平臺線程,避免 JVM 調(diào)度開銷)。
  • 虛擬線程不能調(diào)用 Thread.setDaemon()(守護(hù)線程)、Thread.suspend()、Thread.resume() 方法,調(diào)用會拋出 UnsupportedOperationException。
  • 通過 Executors.newVirtualThreadPerTaskExecutor() 創(chuàng)建的線程池,無需手動調(diào)用 shutdown(),try-with-resources 會自動關(guān)閉。
  • 虛擬線程的優(yōu)先級設(shè)置僅對 JVM 調(diào)度有效,不影響操作系統(tǒng)內(nèi)核線程的優(yōu)先級。
  • 虛擬線程與平臺線程完全兼容,可通過 Thread.isVirtual() 方法判斷線程類型。

2. 模式匹配 for switch(Pattern Matching for switch,JEP 441)—— 簡化分支判斷

2.1 特性說明

JDK21 正式定稿了 switch 模式匹配功能,該特性經(jīng)過 4 輪預(yù)覽迭代(JDK17-JDK20),最終成為正式特性。它擴(kuò)展了 switch 的能力,允許 case 標(biāo)簽使用模式(而非僅常量),支持類型匹配、null 匹配、記錄模式、守衛(wèi)模式等,徹底解決了傳統(tǒng) switch 只能匹配常量、類型判斷繁瑣、空值處理麻煩的問題,讓分支邏輯更簡潔、更安全、更易維護(hù)。

核心增強(qiáng)點(diǎn):

  • 支持類型模式:case 可直接匹配指定類型,無需手動強(qiáng)轉(zhuǎn)。
  • 支持 null 匹配:專門的 case null,無需在 switch 外部判斷空值。
  • 支持 guarded case(條件守衛(wèi)):通過 when 子句添加額外判斷條件(也支持 && 語法)。
  • 支持窮盡性檢查:結(jié)合密封類使用時,編譯器會檢查是否覆蓋所有可能的情況,避免遺漏。
  • 改進(jìn)類型推斷:編譯器能更好地推斷 switch 表達(dá)式的返回類型,減少顯式聲明。

2.2 代碼樣例(5種常見場景)

import java.util.Objects;
/**
 * switch 模式匹配 5種常見場景演示
 * 要求:Java 21+ 版本運(yùn)行(所有特性均為正式特性)
 */
public class SwitchPatternMatchingDemo {
    public static void main(String[] args) {
        // 場景1:類型模式匹配(替代 instanceof + 強(qiáng)轉(zhuǎn))
        Object obj1 = "JDK21";
        String typeResult = switch (obj1) {
            case String s -> "字符串類型,長度:" + s.length();
            case Integer i -> "整數(shù)類型,值:" + i;
            case Double d -> "浮點(diǎn)數(shù)類型,值:" + d;
            default -> "未知類型";
        };
        System.out.println("場景1結(jié)果:" + typeResult);
        // 場景2:null 匹配(無需外部判斷空值)
        String str = null;
        System.out.print("場景2結(jié)果:");
        switch (str) {
            case null -> System.out.println("字符串為null");
            case "JDK" -> System.out.println("字符串是JDK");
            default -> System.out.println("字符串:" + str);
        }
        // 場景3:條件守衛(wèi)(統(tǒng)一使用 when 子句,修復(fù) && 語法錯誤)
        Object obj2 = 42;
        System.out.print("場景3結(jié)果:");
        switch (obj2) {
            case Integer i when i < 18 -> System.out.println("未成年,年齡:" + i);
            case Integer i when i >= 18 && i <= 60 -> System.out.println("成年,年齡:" + i);
            case Integer i -> System.out.println("老年,年齡:" + i);
            case String s when s.length() > 5 -> System.out.println("字符串長度大于5:" + s);
            default -> System.out.println("未知數(shù)據(jù)");
        }
        // 場景4:結(jié)合密封類(窮盡性檢查,編譯器自動校驗(yàn))
        Shape shape = new Circle(5.0);
        double area = switch (shape) {
            case Circle c -> Math.PI * c.radius() * c.radius();
            case Rectangle r -> r.width() * r.height();
            case Triangle t -> (t.base() * t.height()) / 2.0;
            // 無需default,編譯器會檢查密封類的所有子類是否都被覆蓋
        };
        System.out.println("場景4結(jié)果:圖形面積:" + String.format("%.2f", area));
        // 場景5:記錄模式匹配(直接解構(gòu)記錄屬性)
        Person person = new Person("Alice", 30);
        String personInfo = switch (person) {
            case Person(String name, int age) when age < 18 -> "未成年人:" + name;
            case Person(String name, int age) -> "成年人:" + name + "(" + age + "歲)";
        };
        System.out.println("場景5結(jié)果:" + personInfo);
    }
    // 密封類:限制子類只能是指定的幾個類(配合switch實(shí)現(xiàn)窮盡性檢查)
    public sealed interface Shape permits Circle, Rectangle, Triangle {}
    // 密封類的子類,必須使用final、sealed或non-sealed修飾(record默認(rèn)final,符合要求)
    public record Circle(double radius) implements Shape {}
    public record Rectangle(double width, double height) implements Shape {}
    public record Triangle(double base, double height) implements Shape {}
    // 記錄類:用于演示記錄模式匹配
    public record Person(String name, int age) {}
}

2.3 運(yùn)行結(jié)果

場景1結(jié)果:字符串類型,長度:5
場景2結(jié)果:字符串為null
場景3結(jié)果:成年,年齡:42
場景4結(jié)果:圖形面積:78.54
場景5結(jié)果:成年人:Alice(30歲)

2.4 注意事項(xiàng)

  • case 標(biāo)簽的順序會影響匹配結(jié)果,更具體的模式(如帶條件守衛(wèi)的 case)應(yīng)放在前面,避免被更寬泛的模式覆蓋。
  • 當(dāng) switch 的表達(dá)式為 null 時,會優(yōu)先匹配 case null,無需在 switch 前添加 Objects.nonNull() 判斷。
  • 結(jié)合密封類使用時,若遺漏密封類的某個子類,編譯器會直接報(bào)錯(窮盡性檢查),避免運(yùn)行時異常。
  • 模式變量(如 case String s 中的 s)僅在當(dāng)前 case 分支中有效,不可跨分支使用。
  • 支持兩種條件守衛(wèi)語法:when 子句(更優(yōu)雅)和 && 邏輯判斷(更靈活),可根據(jù)場景選擇。

3. 記錄模式(Record Patterns,JEP 440)—— 簡化數(shù)據(jù)解構(gòu)

3.1 特性說明

記錄模式是 JDK21 正式特性,它擴(kuò)展了模式匹配的能力,允許直接解構(gòu)記錄(Record)的組件,無需手動調(diào)用 record 的 getter 方法,同時支持嵌套解構(gòu)、部分解構(gòu),可輕松提取復(fù)雜對象的深層屬性,讓代碼更簡潔、更具可讀性。該特性從 JDK19 開始預(yù)覽,經(jīng)過兩輪優(yōu)化后正式定稿,常與 switch 模式匹配配合使用,是處理不可變數(shù)據(jù)的最佳實(shí)踐。

核心價值:

  • 簡化記錄解構(gòu):直接提取 record 的組件,無需調(diào)用 xxx() 方法。
  • 支持嵌套解構(gòu):可多層嵌套,提取復(fù)雜對象的深層屬性。
  • 支持部分解構(gòu):無需關(guān)注所有組件,可忽略不需要的屬性。
  • 與 switch/instanceof 無縫集成:實(shí)現(xiàn)復(fù)雜數(shù)據(jù)的快速判斷和解構(gòu)。
  • 編譯時安全:通過編譯時檢查確保屬性訪問的正確性,避免類型錯誤。

3.2 代碼樣例(基礎(chǔ)解構(gòu) + 嵌套解構(gòu) + 部分解構(gòu))

import java.time.LocalDate;
/**
 * 記錄(Record)模式匹配 - 解構(gòu)演示(修復(fù)未命名模式兼容問題)
 * 要求:Java 21+
 */
public class RecordPatternMatchingDemo {
    // 基礎(chǔ)記錄(無嵌套)
    public record Point(int x, int y) {}
    // 嵌套記錄(包含Point記錄)
    public record ColoredPoint(Point point, String color) {}
    // 多層嵌套記錄(包含ColoredPoint記錄)
    public record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {}
    // 復(fù)雜業(yè)務(wù)記錄(包含嵌套記錄和普通類型)
    public record Order(String orderId, LocalDate createTime, ColoredPoint deliveryAddress) {}
    public static void main(String[] args) {
        // 場景1:基礎(chǔ)記錄解構(gòu)(直接提取Point的x和y)
        Point point = new Point(10, 20);
        if (point instanceof Point(int x, int y)) {
            System.out.println("場景1:基礎(chǔ)解構(gòu) - x=" + x + ", y=" + y);
        }
        // 場景2:嵌套記錄解構(gòu)(提取ColoredPoint中的Point組件)
        ColoredPoint coloredPoint = new ColoredPoint(new Point(5, 8), "red");
        if (coloredPoint instanceof ColoredPoint(Point(int x, int y), String color)) {
            System.out.println("場景2:嵌套解構(gòu) - x=" + x + ", y=" + y + ", color=" + color);
        }
        // 場景3:多層嵌套解構(gòu)(提取Rectangle中的深層Point組件)
        Rectangle rectangle = new Rectangle(
                new ColoredPoint(new Point(1, 2), "blue"),
                new ColoredPoint(new Point(3, 4), "blue")
        );
        if (rectangle instanceof Rectangle(
                ColoredPoint(Point(int x1, int y1), String color1),
                ColoredPoint(Point(int x2, int y2), String color2)
        )) {
            System.out.println("場景3:多層嵌套解構(gòu) - " +
                    "左上角(" + x1 + "," + y1 + "," + color1 + "), " +
                    "右下角(" + x2 + "," + y2 + "," + color2 + ")");
        }
        // 場景4:部分解構(gòu)(替換_為顯式命名的忽略變量,解決兼容問題)
        Order order = new Order("ORD-2024-001", LocalDate.now(), new ColoredPoint(new Point(100, 200), "green"));
        if (order instanceof Order(String orderId, LocalDate ignoreCreateTime, ColoredPoint(Point(int x, int y), String ignoreColor))) {
            // 忽略ignoreCreateTime和ignoreColor,僅使用需要的變量
            System.out.println("場景4:部分解構(gòu) - 訂單ID:" + orderId + ", 配送坐標(biāo):(" + x + "," + y + ")");
        }
        // 場景5:結(jié)合switch模式匹配(同樣替換_為ignore變量)
        Object obj = new ColoredPoint(new Point(3, 5), "green");
        String deconstructionResult = switch (obj) {
            case Point(int x, int y) -> "Point: (" + x + "," + y + ")";
            case ColoredPoint(Point(int x, int y), String color) -> "ColoredPoint: (" + x + "," + y + "), " + color;
            case Rectangle(ColoredPoint p1, ColoredPoint p2) -> "Rectangle: " + p1 + ", " + p2;
            case Order(String orderId, LocalDate ignoreTime, ColoredPoint ignoreAddr) -> "Order: " + orderId;
            default -> "未知記錄類型";
        };
        System.out.println("場景5:switch結(jié)合記錄模式 - " + deconstructionResult);
    }
}

3.3 運(yùn)行結(jié)果

場景1:基礎(chǔ)解構(gòu) - x=10, y=20
場景2:嵌套解構(gòu) - x=5, y=8, color=red
場景3:多層嵌套解構(gòu) - 左上角(1,2,blue), 右下角(3,4,blue)
場景4:部分解構(gòu) - 訂單ID:ORD-2024-001, 配送坐標(biāo):(100,200)
場景5:switch結(jié)合記錄模式 - ColoredPoint: (3,5), green

3.4 注意事項(xiàng)

  • 記錄模式僅適用于 record 類,普通類無法使用(record 類是不可變的,組件具有固定的 getter 方法)。
  • 嵌套解構(gòu)時,需保證每層的模式匹配正確,若某一層不匹配,則整個模式匹配失敗。
  • 可使用 var 簡化變量聲明,例如 Point(var x, var y),編譯器會自動推斷變量類型。
  • 部分解構(gòu)時,可使用下劃線 _ 表示不需要的組件,提高代碼可讀性。
  • 記錄模式可與 instanceof、switch 配合使用,尤其適合處理 DTO、VO 等不可變數(shù)據(jù)對象。

4. 密封類(Sealed Classes,JEP 409)—— 控制類繼承

4.1 特性說明

密封類在 JDK21 中正式定型,它允許開發(fā)者限制類或接口的繼承/實(shí)現(xiàn)范圍,明確指定哪些類可以繼承它,避免不必要的繼承和擴(kuò)展,提升代碼的可維護(hù)性和安全性。密封類從 JDK15 開始預(yù)覽,經(jīng)過多輪優(yōu)化后正式成為標(biāo)準(zhǔn)特性,常與 switch 模式匹配配合使用,實(shí)現(xiàn)窮盡性檢查,確保分支邏輯覆蓋所有可能的子類。

核心規(guī)則:

  • 密封類使用 sealed 修飾,通過 permits 關(guān)鍵字指定允許繼承的子類。
  • 密封類的子類必須使用以下三種修飾符之一:
    • final:不可再被繼承。
    • sealed:可繼續(xù)限制子類(需再次使用 permits 指定)。
    • non-sealed:開放繼承,允許任意類繼承。
  • 密封接口的實(shí)現(xiàn)類,也需遵循上述修飾符規(guī)則。
  • 密封類及其子類必須在同一個包下(若使用模塊,需在同一個模塊下)。

4.2 代碼樣例(密封類 + 密封接口 + 多層密封)

package org.example.model;
/**
 * 密封類 + 密封接口 + 多層密封 演示
 * 要求:Java 21+
 */
public class SealedClassDemo {
    public static void main(String[] args) {
        // 測試密封類(靜態(tài)內(nèi)部類可直接實(shí)例化)
        Animal cat = new Cat();
        Animal dog = new Dog();
        Animal puppy = new Puppy();
        Animal bird = new Bird();
        System.out.println("貓的叫聲:" + cat.makeSound());
        System.out.println("狗的叫聲:" + dog.makeSound());
        System.out.println("小狗的叫聲:" + puppy.makeSound());
        System.out.println("鳥的叫聲:" + bird.makeSound());
        // 測試密封接口
        Fruit apple = new Apple();
        Fruit banana = new Banana();
        Fruit orange = new Orange();
        System.out.println("蘋果的顏色:" + apple.getColor());
        System.out.println("香蕉的顏色:" + banana.getColor());
        System.out.println("橙子的顏色:" + orange.getColor());
        // 測試窮盡性檢查(switch + 密封類)
        printAnimalType(cat);
        printAnimalType(dog);
        printAnimalType(puppy);
        printAnimalType(bird);
    }
    // 給sealed類添加abstract修飾符(包含抽象方法必須聲明為抽象類)
    // 密封+抽象類:僅允許 Cat、Dog、Bird 繼承
    public static abstract sealed class Animal permits Cat, Dog, Bird {
        public abstract String makeSound();
    }
    // final 子類:不可再繼承
    public static final class Cat extends Animal {
        @Override
        public String makeSound() {
            return "喵喵喵";
        }
    }
    // sealed 子類:可繼續(xù)限制子類(僅允許 Puppy 繼承)
    public static sealed class Dog extends Animal permits Puppy {
        @Override
        public String makeSound() {
            return "汪汪汪";
        }
    }
    // Dog 的子類,final 修飾
    public static final class Puppy extends Dog {
        @Override
        public String makeSound() {
            return "嗚嗚嗚(小狗叫)";
        }
    }
    // non-sealed 子類:開放繼承,允許任意類繼承
    public static non-sealed class Bird extends Animal {
        @Override
        public String makeSound() {
            return "嘰嘰喳喳";
        }
    }
    // 密封接口:僅允許 Apple、Banana、Orange 實(shí)現(xiàn)
    public static sealed interface Fruit permits Apple, Banana, Orange {
        String getColor();
    }
    public static final class Apple implements Fruit {
        @Override
        public String getColor() {
            return "紅色";
        }
    }
    public static final class Banana implements Fruit {
        @Override
        public String getColor() {
            return "黃色";
        }
    }
    public static non-sealed class Orange implements Fruit {
        @Override
        public String getColor() {
            return "橙色";
        }
    }
    // 結(jié)合switch實(shí)現(xiàn)窮盡性檢查
    // 調(diào)整匹配順序(先匹配Puppy,再匹配Dog),讓編譯器識別窮盡性
    private static void printAnimalType(Animal animal) {
        String type = switch (animal) {
            case Cat ignore -> "貓科動物";
            case Puppy ignore -> "犬科動物(小狗)"; // 先匹配Puppy(Dog的子類)
            case Dog ignore -> "犬科動物(成年犬)";  // 再匹配普通Dog
            case Bird ignore -> "鳥類動物";
        };
        System.out.println("動物類型:" + type);
    }
}

4.3 運(yùn)行結(jié)果

貓的叫聲:喵喵喵
狗的叫聲:汪汪汪
小狗的叫聲:嗚嗚嗚(小狗叫)
鳥的叫聲:嘰嘰喳喳
蘋果的顏色:紅色
香蕉的顏色:黃色
橙子的顏色:橙色
動物類型:貓科動物
動物類型:犬科動物(成年犬)
動物類型:犬科動物(小狗)
動物類型:鳥類動物

4.4 注意事項(xiàng)

  • 密封類的 permits 關(guān)鍵字后,必須列出所有允許繼承的子類,不能遺漏。
  • 密封類不能是 final 的(final 類不可繼承,與密封類的設(shè)計(jì)初衷沖突)。
  • 非密封子類(non-sealed)可以被任意類繼承,打破密封類的限制,適合需要靈活擴(kuò)展的場景。
  • 密封類與 switch 模式匹配配合時,編譯器會自動檢查是否覆蓋所有子類,避免遺漏分支。
  • 密封接口的實(shí)現(xiàn)類同樣需要遵循修飾符規(guī)則,確保接口的實(shí)現(xiàn)范圍可控。

5. 分代 ZGC(Generational ZGC,JEP 439)—— 提升 GC 性能

5.1 特性說明

ZGC 是 Java 推出的低延遲垃圾收集器,JDK21 正式將分代 ZGC 從實(shí)驗(yàn)特性轉(zhuǎn)為正式特性(JEP 439 Final 狀態(tài)),其核心是將堆內(nèi)存分為年輕代和老年代,針對不同代的對象采用差異化收集策略:

  • 年輕代對象生命周期短,采用頻繁、快速的收集策略;
  • 老年代對象生命周期長,采用低頻率、高效率的收集策略。

這一優(yōu)化極大提升了垃圾收集的吞吐量和響應(yīng)速度,尤其適合大堆內(nèi)存場景(如 10GB 以上堆內(nèi)存)。

核心優(yōu)勢:

  • 低延遲:GC 停頓時間控制在毫秒級甚至亞毫秒級,幾乎不影響程序正常運(yùn)行;
  • 高吞吐量:分代收集減少了不必要的垃圾掃描范圍,提升垃圾收集效率;
  • 大堆支持:64 位系統(tǒng)下最大支持 16TB 堆內(nèi)存(設(shè)計(jì)上限),可輕松應(yīng)對大內(nèi)存應(yīng)用場景;
  • 并發(fā)處理:年輕代和老年代的核心垃圾收集流程均為并發(fā)執(zhí)行,應(yīng)用線程無需長時間阻塞;
  • 動態(tài)內(nèi)存布局:可根據(jù)應(yīng)用實(shí)際內(nèi)存需求自動調(diào)整年輕代 / 老年代的大小;
  • 無縫遷移:無需修改業(yè)務(wù)代碼,僅通過 JVM 參數(shù)即可啟用,無侵入性。

官方規(guī)劃:OpenJDK 計(jì)劃在 JDK25 及后續(xù)版本中將分代 ZGC 設(shè)為默認(rèn)垃圾收集器,后續(xù)會逐步移除非分代 ZGC 實(shí)現(xiàn),ZGenerational 選項(xiàng)也將不再需要手動配置。

5.2 啟用方式(JVM 參數(shù))

# 啟用分代 ZGC(JDK21 正式特性,無需解鎖實(shí)驗(yàn)性選項(xiàng))
-XX:+UseZGC -XX:+ZGenerational
# 可選參數(shù)(優(yōu)化大堆場景)
-XX:ZHeapSize=10G        # 設(shè)置堆內(nèi)存總大小為10G
-XX:MaxGCPauseMillis=10  # 建議最大GC停頓時間(ZGC 會盡力滿足,非強(qiáng)制)
-XX:ZYoungGenSize=2G     # 設(shè)置年輕代初始大小為2G(默認(rèn)自動動態(tài)調(diào)整,無需手動配置)

5.3 實(shí)際應(yīng)用示例

# 運(yùn)行Spring Boot應(yīng)用并啟用分代ZGC(JDK21+)
java -XX:+UseZGC -XX:+ZGenerational -XX:ZHeapSize=20G -jar your-app.jar
# 進(jìn)階配置(指定年輕代大小+停頓時間目標(biāo))
java -XX:+UseZGC -XX:+ZGenerational -XX:ZHeapSize=32G -XX:ZYoungGenSize=4G -XX:MaxGCPauseMillis=5 -jar your-app.jar

5.4 注意事項(xiàng)

  • 版本要求:分代 ZGC 僅在 JDK21 及以上版本支持,JDK21 之前的 ZGC 無分代收集能力;
  • 排他性:啟用分代 ZGC 后,不可同時啟用 G1、Shenandoah 等其他垃圾收集器,避免 JVM 參數(shù)沖突;
  • 場景適配:適合大堆內(nèi)存場景(堆內(nèi)存 ≥ 4GB),小堆內(nèi)存場景(<4GB)使用 G1 收集器性價比更高;
  • 參數(shù)原則:分代 ZGC 會自動動態(tài)調(diào)整年輕代 / 老年代大小,除非有明確的性能調(diào)優(yōu)需求,否則無需手動配置 ZYoungGenSize;
  • 技術(shù)依賴:依賴染色指針(Colored Pointers)和讀屏障(Load Barriers)技術(shù),64 位主流操作系統(tǒng) / 虛擬機(jī)環(huán)境默認(rèn)已啟用,無需額外配置;
  • 堆上限:ZGC 設(shè)計(jì)最大堆大小為 16TB(JDK21),實(shí)際可用上限受操作系統(tǒng)、硬件物理內(nèi)存限制,無法突破 16TB。

總結(jié)

  1. 核心參數(shù)修正:
    • 移除多余的 -XX:+UnlockExperimentalVMOptions(JDK21 分代 ZGC 是正式特性,無需解鎖);
    • 錯誤參數(shù) ZYoungGenerationSize → 正確參數(shù) ZYoungGenSizeGenGeneration 的官方縮寫,JVM 僅識別縮寫形式);
    • ZGC 最大堆上限為 16TB(非 “16TB 以上”)。
  2. 啟用原則:優(yōu)先使用默認(rèn)參數(shù),僅在大堆場景(≥4GB)手動調(diào)整堆總大小(ZHeapSize),年輕代大?。?code>ZYoungGenSize)無需主動配置。
  3. 關(guān)鍵驗(yàn)證:若在 JVM 啟動時傳入 ZYoungGenerationSize,會直接提示 Unrecognized VM option 'ZYoungGenerationSize',而 ZYoungGenSize 是 JDK21 分代 ZGC 的官方標(biāo)準(zhǔn)參數(shù)。

6. 序列化集合(Sequenced Collections,JEP 431)—— 有序集合標(biāo)準(zhǔn)化

6.1 特性說明

  • JDK21 正式引入 Sequenced Collections(序列化集合,又稱有序集合),這是一種具有確定出現(xiàn)順序(encounter order)的集合,無論遍歷多少次,元素的出現(xiàn)順序始終固定。它提供了統(tǒng)一的接口和方法來處理集合的首尾元素、反向視圖等,解決了以往不同集合(List、Set、Map)處理順序操作的 API 不一致問題。
  • 核心優(yōu)勢:
    • 核心接口關(guān)系:
    • 統(tǒng)一接口:提供 SequencedCollectionSequencedSet、SequencedMap 三大核心接口,標(biāo)準(zhǔn)化順序操作。
    • 有序性保證:元素插入順序與遍歷順序一致,支持首尾元素快速訪問。
  • 線程安全:部分實(shí)現(xiàn)(如 ConcurrentLinkedDeque)通過 Sequenced Locks 機(jī)制實(shí)現(xiàn)線程安全,支持多線程并發(fā)讀寫。
  • 可擴(kuò)展性:設(shè)計(jì)考慮了大量數(shù)據(jù)的并發(fā)訪問,適合高并發(fā)場景。
  • 反向視圖:通過 reversed() 方法快速獲取反向順序的集合視圖,無需手動反轉(zhuǎn)。
    • SequencedCollection:繼承 Collection,基礎(chǔ)有序集合接口。
    • SequencedSet:繼承 SequencedCollectionSet,有序不重復(fù)集合接口。
    • SequencedMap:繼承 Map,有序鍵值對映射接口。

6.2 代碼樣例(三大接口完整演示)

import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.SequencedCollection;
import java.util.SequencedMap;
import java.util.SequencedSet;
/**
 * 有序集合(Sequenced Collections)三大接口演示
 * 注意:使用LinkedList(而非ArrayList),因?yàn)槠渲С謅ddFirst()/addLast()
 */
public class SequencedCollectionsDemo {
    public static void main(String[] args) {
        // 場景1:SequencedCollection 演示(以 LinkedList 為例,支持addFirst/addLast)
        System.out.println("=== 場景1:SequencedCollection 演示 ===");
        SequencedCollection<Integer> collection = new LinkedList<>();
        collection.add(1);
        collection.addFirst(0); // 添加到頭部(LinkedList支持,ArrayList不支持)
        collection.addLast(2); // 添加到尾部
        System.out.println("集合元素:" + collection);
        System.out.println("第一個元素:" + collection.getFirst());
        System.out.println("最后一個元素:" + collection.getLast());
        SequencedCollection<Integer> reversedCollection = collection.reversed();
        System.out.println("反向集合:" + reversedCollection);
        collection.removeFirst(); // 刪除頭部元素
        collection.removeLast(); // 刪除尾部元素
        System.out.println("刪除首尾后:" + collection);
        // 場景2:SequencedSet 演示(以 LinkedHashSet 為例)
        System.out.println("\n=== 場景2:SequencedSet 演示 ===");
        SequencedSet<Integer> set = new LinkedHashSet<>();
        set.add(3);
        set.add(1);
        set.add(2);
        set.addFirst(0); // 添加到頭部
        set.addLast(4); // 添加到尾部
        System.out.println("Set元素(有序不重復(fù)):" + set);
        System.out.println("第一個元素:" + set.getFirst());
        System.out.println("最后一個元素:" + set.getLast());
        SequencedSet<Integer> reversedSet = set.reversed();
        System.out.println("反向Set:" + reversedSet);
        // 場景3:SequencedMap 演示(以 LinkedHashMap 為例)
        System.out.println("\n=== 場景3:SequencedMap 演示 ===");
        SequencedMap<Integer, String> map = new LinkedHashMap<>();
        map.put(1, "Apple");
        map.put(2, "Banana");
        map.put(3, "Orange");
        map.putFirst(0, "Grape"); // 添加到頭部
        map.putLast(4, "Mango"); // 添加到尾部
        System.out.println("Map元素:" + map);
        System.out.println("第一個鍵值對:" + map.firstEntry());
        System.out.println("最后一個鍵值對:" + map.lastEntry());
        // 獲取有序的key、value、entry集合
        System.out.println("有序key集合:" + map.sequencedKeySet());
        System.out.println("有序value集合:" + map.sequencedValues());
        System.out.println("有序entry集合:" + map.sequencedEntrySet());
        // 移除首尾鍵值對
        map.pollFirstEntry(); // 移除并返回第一個鍵值對
        map.pollLastEntry(); // 移除并返回最后一個鍵值對
        System.out.println("移除首尾后:" + map);
        // 反向Map
        SequencedMap<Integer, String> reversedMap = map.reversed();
        System.out.println("反向Map:" + reversedMap);
    }
}

6.3 運(yùn)行結(jié)果

=== 場景1:SequencedCollection 演示 ===
集合元素:[0, 1, 2]
第一個元素:0
最后一個元素:2
反向集合:[2, 1, 0]
刪除首尾后:[1]

=== 場景2:SequencedSet 演示 ===
Set元素(有序不重復(fù)):[0, 3, 1, 2, 4]
第一個元素:0
最后一個元素:4
反向Set:[4, 2, 1, 3, 0]

=== 場景3:SequencedMap 演示 ===
Map元素:{0=Grape, 1=Apple, 2=Banana, 3=Orange, 4=Mango}
第一個鍵值對:0=Grape
最后一個鍵值對:4=Mango
有序key集合:[0, 1, 2, 3, 4]
有序value集合:[Grape, Apple, Banana, Orange, Mango]
有序entry集合:[0=Grape, 1=Apple, 2=Banana, 3=Orange, 4=Mango]
移除首尾后:{1=Apple, 2=Banana, 3=Orange}
反向Map:{3=Orange, 2=Banana, 1=Apple}

6.4 注意事項(xiàng)

實(shí)現(xiàn)類說明:

  • List 接口繼承 SequencedCollectionLinkedList 重寫 addFirst()/addLast() 可正常使用,ArrayList 的同名方法拋 UnsupportedOperationException);
  • Deque 接口繼承 SequencedCollection(如 ConcurrentLinkedDeque、ArrayDeque);
  • LinkedHashSet、TreeSet(實(shí)現(xiàn) NavigableSet)實(shí)現(xiàn) SequencedSet;
  • LinkedHashMapTreeMap(實(shí)現(xiàn) NavigableMap)實(shí)現(xiàn) SequencedMap。

線程安全:SequencedCollections 接口本身不保證線程安全,需使用線程安全的實(shí)現(xiàn)類(如 ConcurrentLinkedDeque)或手動加鎖;ConcurrentLinkedDeque 的線程安全基于 CAS 機(jī)制實(shí)現(xiàn),無 “Sequenced Locks” 概念。

反向視圖:reversed() 方法返回的是原集合的反向視圖(而非新集合),修改原集合會同步影響反向視圖,反之亦然。

空集合處理:調(diào)用空集合的 getFirst()、getLast() 方法會拋出 NoSuchElementException,需提前通過 isEmpty() 判斷集合是否為空。

與傳統(tǒng)方法對比:

  • addFirst()/addLast() 是對 Deque 同名方法的標(biāo)準(zhǔn)化擴(kuò)展(覆蓋到所有 List),而非 “替代”;
  • sequencedKeySet()Map.keySet()有序增強(qiáng)版(返回 SequencedSet),二者共存,并非 “替代”。

二、預(yù)覽特性(需啟用 --enable-preview 參數(shù))

預(yù)覽特性是 JDK 中已實(shí)現(xiàn)但尚未正式定型的特性,可能在未來版本中優(yōu)化或調(diào)整,使用時需在編譯和運(yùn)行時添加 --enable-preview 參數(shù)(具體用法見每個特性的說明)。JDK21 中有多個實(shí)用預(yù)覽特性,以下重點(diǎn)講解最常用的 5 個。

1. 字符串模板(String Templates,JEP 430)—— 簡化字符串拼接

1.1 特性說明

  • 字符串模板是 JDK21 的預(yù)覽特性,類似 Python 的 f-string、JavaScript 的模板字符串,允許在字符串中直接嵌入表達(dá)式,無需使用 + 拼接或 String.format(),支持三種內(nèi)置模板處理器,同時支持自定義處理器,解決了傳統(tǒng)字符串拼接繁瑣、易出錯、可讀性差的問題。
  • 核心優(yōu)勢:
  • 內(nèi)置模板處理器:
    • 簡潔高效:直接嵌入表達(dá)式,無需拼接,代碼更簡潔。
    • 類型安全:表達(dá)式類型自動適配,無需手動轉(zhuǎn)換。
    • 支持格式化:通過 FMT 處理器支持格式化說明符(如 %.2f、%-10s)。
    • 支持自定義:可實(shí)現(xiàn) StringTemplate.Processor 接口創(chuàng)建自定義處理器。
    • 多行支持:支持多行字符串模板,保留換行和縮進(jìn)格式。
    • 表達(dá)式靈活:支持變量、方法調(diào)用、復(fù)雜計(jì)算、注釋等多種表達(dá)式形式。
    • STR:基礎(chǔ)處理器,自動執(zhí)行字符串插值,將表達(dá)式替換為字符串值。
    • FMT:格式化處理器,支持格式化說明符(如 %.2f、%-10s)。
    • RAW:原始處理器,返回 StringTemplate 對象,不自動處理插值,用于自定義處理。

1.2 代碼樣例(完整用法演示)

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
/**
 * 字符串模板(預(yù)覽特性)完整用法演示
 * 編譯命令:javac --enable-preview --release 21 StringTemplateDemo.java
 * 運(yùn)行命令:java --enable-preview StringTemplateDemo
 */
public class StringTemplateDemo {
    // 測試方法:用于表達(dá)式調(diào)用
    private static String getName() {
        return "Java開發(fā)者";
    }
    // 自定義模板處理器:轉(zhuǎn)換為大寫格式(兼容null參數(shù))
    private static class UpperCaseProcessor implements StringTemplate.Processor<String, RuntimeException> {
        @Override
        public String process(StringTemplate st) {
            // 拼接模板文本和表達(dá)式值,轉(zhuǎn)換為大寫
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < st.fragments().size(); i++) {
                sb.append(st.fragments().get(i));
                if (i < st.arguments().size()) {
                    Object arg = st.arguments().get(i);
                    // 兼容null參數(shù),避免空指針
                    sb.append(arg == null ? "null" : arg.toString().toUpperCase());
                }
            }
            return sb.toString();
        }
    }
    public static void main(String[] args) {
        // 基礎(chǔ)信息
        String name = "Alice";
        int age = 30;
        double salary = 15000.50;
        String userInput = "<script>alert('攻擊')</script>"; // 修正:設(shè)置有注入風(fēng)險(xiǎn)的輸入
        // 場景1:STR處理器(基礎(chǔ)插值)
        String info1 = STR."姓名:\{name},年齡:\{age},薪資:\{salary}";
        System.out.println("場景1:STR基礎(chǔ)插值 - " + info1);
        // 場景2:STR處理器(表達(dá)式調(diào)用:變量、方法、計(jì)算)
        String info2 = STR."靜態(tài)變量:\{name},方法調(diào)用:\{getName()},計(jì)算結(jié)果:\{10 + 20 == 30 ? "正確" : "錯誤"}";
        System.out.println("場景2:STR表達(dá)式調(diào)用 - " + info2);
        // 場景3:FMT處理器(格式化)
        String info3 = FMT."姓名:%-10s\{name},年齡:%03d\{age},薪資:%.2f\{salary}";
        System.out.println("場景3:FMT格式化 - " + info3);
        // 場景4:RAW處理器(原始模板,自定義處理)
        StringTemplate rawTemplate = RAW."姓名:\{name},年齡:\{age}";
        System.out.println("場景4:RAW原始文本 - " + rawTemplate.text());
        System.out.println("場景4:RAW插值后(STR處理) - " + STR.process(rawTemplate));
        // 場景5:多行字符串模板
        String info4 = STR."""
                個人信息:
                姓名:\{name}
                年齡:\{age}歲
                薪資:\{salary}元/月
                當(dāng)前時間:\{
                    // 多行表達(dá)式支持注釋
                    DateTimeFormatter.ofPattern("HH:mm:ss")
                                    .format(LocalTime.now())
                }
                """;
        System.out.println("場景5:多行模板 - " + info4);
        // 場景6:自定義模板處理器(修正調(diào)用語法)
        UpperCaseProcessor upperProcessor = new UpperCaseProcessor();
        StringTemplate upperTemplate = STR."姓名:\{name},年齡:\{age}";
        String info5 = upperProcessor.process(upperTemplate);
        System.out.println("場景6:自定義處理器(大寫) - " + info5);
        // 場景7:安全說明:STR/FMT不自動轉(zhuǎn)義,防注入需自定義處理器
        String unsafeInfo = STR."用戶輸入:\{userInput}";
        System.out.println("場景7:未轉(zhuǎn)義輸入 - " + unsafeInfo);
    }
}

1.3 運(yùn)行結(jié)果

場景1:STR基礎(chǔ)插值 - 姓名:Alice,年齡:30,薪資:15000.5
場景2:STR表達(dá)式調(diào)用 - 靜態(tài)變量:Alice,方法調(diào)用:Java開發(fā)者,計(jì)算結(jié)果:正確
場景3:FMT格式化 - 姓名:Alice     ,年齡:030,薪資:15000.50
場景4:RAW原始文本 - 姓名:\{name},年齡:\{age}
場景4:RAW插值后(STR處理) - 姓名:Alice,年齡:30
場景5:多行模板 - 個人信息:
姓名:Alice
年齡:30歲
薪資:15000.5元/月
當(dāng)前時間:14:35:22

場景6:自定義處理器(大寫) - 姓名:ALICE,年齡:30
場景7:未轉(zhuǎn)義輸入 - 用戶輸入:<script>alert('攻擊')</script>

1.4 注意事項(xiàng)

  • 啟用方式:必須在編譯和運(yùn)行時添加 --enable-preview --release 21 參數(shù)(JDK22/23 同理),否則會提示 “字符串模板是預(yù)覽特性,需啟用預(yù)覽模式”;
  • 安全說明:STR 和 FMT 處理器不會自動轉(zhuǎn)義特殊字符(如 <>/'/"),處理用戶輸入時需自定義處理器實(shí)現(xiàn) XSS / 注入防護(hù);
  • 多行模板:使用 “”" 包裹,保留換行和縮進(jìn)格式,表達(dá)式嵌入方式與單行一致,多行表達(dá)式內(nèi)可寫注釋;
  • 自定義處理器:
    • 實(shí)現(xiàn) StringTemplate.Processor 接口的 process 方法,入?yún)?StringTemplate(包含模板文本片段 fragments() 和表達(dá)式參數(shù) arguments());
    • 調(diào)用時需先通過 STR/RAW 創(chuàng)建 StringTemplate 對象,再傳入處理器的 process() 方法;
    • 需處理參數(shù)為 null 的情況,避免空指針異常;
  • 表達(dá)式限制:模板中的表達(dá)式不能包含未聲明的變量,表達(dá)式執(zhí)行拋出的異常會直接傳播,需手動捕獲處理;
  • 版本說明:JDK21/22/23 中 String Templates 均為預(yù)覽特性,正式版尚未發(fā)布,生產(chǎn)環(huán)境慎用。

2. 結(jié)構(gòu)化并發(fā)(Structured Concurrency,JEP 453)—— 簡化并發(fā)任務(wù)管理

2.1 特性說明

結(jié)構(gòu)化并發(fā)是 JDK21 的預(yù)覽特性(JDK23 正式轉(zhuǎn)正),旨在簡化多線程并發(fā)任務(wù)的管理,解決傳統(tǒng)并發(fā)編程中線程泄漏、任務(wù)間依賴混亂、異常處理繁瑣等問題。它將一組相關(guān)的并發(fā)任務(wù)視為一個整體,統(tǒng)一管理生命周期(啟動、執(zhí)行、取消、終止),確保所有子任務(wù)完成后主線程再繼續(xù)執(zhí)行,同時支持異常統(tǒng)一捕獲和任務(wù)取消擴(kuò)散,讓并發(fā)代碼更具可讀性、可維護(hù)性和安全性。
核心優(yōu)勢:

  • 生命周期統(tǒng)一:子任務(wù)與父任務(wù)綁定,父任務(wù)取消 / 終止時,所有子任務(wù)自動取消,避免線程泄漏;
  • 異常集中處理:子任務(wù)拋出的異常會被收集到 scope 中,可統(tǒng)一獲取和處理,無需單獨(dú)捕獲;
  • 任務(wù)依賴清晰:通過結(jié)構(gòu)化層級明確任務(wù)間的父子關(guān)系,避免并發(fā)任務(wù)邏輯混亂;
  • 與虛擬線程兼容:可靈活搭配虛擬線程使用,輕松管理大量并發(fā)子任務(wù),提升高并發(fā)場景性能;
  • 取消擴(kuò)散:父任務(wù)取消時,會自動中斷所有未完成的子任務(wù),避免資源浪費(fèi);
  • 自動資源管理:結(jié)合 try-with-resources 語法,確保 scope 自動關(guān)閉,杜絕線程泄漏。

2.2 代碼樣例(基礎(chǔ)使用 + 異常處理 + 取消任務(wù))

import java.util.concurrent.ExecutionException;
import java.util.concurrent.StructuredTaskScope;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
 * 結(jié)構(gòu)化并發(fā)(預(yù)覽特性)演示
 * 編譯命令:javac --enable-preview --release 21 StructuredConcurrencyDemo.java
 * 運(yùn)行命令:java --enable-preview StructuredConcurrencyDemo
 */
public class StructuredConcurrencyDemo {
    public static void main(String[] args) throws InterruptedException {
        // 場景1:基礎(chǔ)結(jié)構(gòu)化并發(fā)(父子任務(wù)綁定)
        System.out.println("=== 場景1:基礎(chǔ)結(jié)構(gòu)化并發(fā) ===");
        try (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) {
            // 提交子任務(wù)1(虛擬線程需顯式指定線程工廠,默認(rèn)平臺線程)
            scope.fork(() -> {
                TimeUnit.MILLISECONDS.sleep(100);
                return "子任務(wù)1執(zhí)行完成";
            });
            // 提交子任務(wù)2
            scope.fork(() -> {
                TimeUnit.MILLISECONDS.sleep(200);
                return "子任務(wù)2執(zhí)行完成";
            });
            // 等待子任務(wù)完成(ShutdownOnSuccess:任一成功則關(guān)閉其他任務(wù))
            scope.join();
            // 獲取成功完成的子任務(wù)結(jié)果(第一個成功的)
            System.out.println("成功結(jié)果:" + scope.result());
        } // try-with-resources 自動關(guān)閉scope
        // 場景2:異常處理(子任務(wù)拋出異常,父任務(wù)統(tǒng)一捕獲)
        System.out.println("\n=== 場景2:異常處理 ===");
        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
            // 子任務(wù)3:拋出異常
            scope.fork(() -> {
                TimeUnit.MILLISECONDS.sleep(50);
                System.out.println("子任務(wù)3執(zhí)行中");
                throw new RuntimeException("子任務(wù)3執(zhí)行失敗");
            });
            // 子任務(wù)4:因子任務(wù)3失敗,會被提前終止,不會執(zhí)行到打印
            scope.fork(() -> {
                TimeUnit.MILLISECONDS.sleep(150);
                System.out.println("子任務(wù)4執(zhí)行完成");
                return "子任務(wù)4成功";
            });
            try {
                scope.join(); // 等待,ShutdownOnFailure:任一失敗則關(guān)閉
            } catch (ExecutionException e) {
                // 捕獲封裝的異常,實(shí)際異常在scope.failures()中
                System.out.println("捕獲到執(zhí)行異常:" + e.getMessage());
            }
            // 遍歷所有子任務(wù)的異常(核心:從failures()獲?。?
            scope.failures().forEach(ex -> System.out.println("子任務(wù)異常:" + ex.getMessage()));
        }
        // 場景3:手動取消任務(wù)
        System.out.println("\n=== 場景3:手動取消任務(wù) ===");
        try (var scope = new StructuredTaskScope<String>()) {
            // 子任務(wù)5:耗時任務(wù)
            var future1 = scope.fork(() -> {
                try {
                    TimeUnit.MILLISECONDS.sleep(1000);
                    return "子任務(wù)5執(zhí)行完成";
                } catch (InterruptedException e) {
                    System.out.println("子任務(wù)5被取消");
                    return null;
                }
            });
            // 子任務(wù)6:快速完成
            var future2 = scope.fork(() -> {
                TimeUnit.MILLISECONDS.sleep(100);
                return "子任務(wù)6執(zhí)行完成";
            });
            // 等待150ms,或所有子任務(wù)完成
            try {
                scope.joinUntil(System.currentTimeMillis() + 150);
                if (future2.isDone()) {
                    System.out.println("子任務(wù)6結(jié)果:" + future2.resultNow());
                    scope.shutdown(); // 觸發(fā)子任務(wù)中斷(子任務(wù)5)
                }
            } catch (TimeoutException e) {
                System.out.println("等待超時");
            }
        }
    }
}

2.3 運(yùn)行結(jié)果

=== 場景1:基礎(chǔ)結(jié)構(gòu)化并發(fā) ===
成功結(jié)果:子任務(wù)1執(zhí)行完成

=== 場景2:異常處理 ===
子任務(wù)3執(zhí)行中
捕獲到執(zhí)行異常:java.lang.RuntimeException: 子任務(wù)3執(zhí)行失敗
子任務(wù)異常:子任務(wù)3執(zhí)行失敗

=== 場景3:手動取消任務(wù) ===
子任務(wù)6結(jié)果:子任務(wù)6執(zhí)行完成
子任務(wù)5被取消

2.4 注意事項(xiàng)

  • 啟用方式:需在編譯和運(yùn)行時添加 --enable-preview --release 21 參數(shù)(JDK22/23 同理,JDK23 該特性已正式發(fā)布,無需預(yù)覽參數(shù));
  • scope 生命周期:必須使用 try-with-resources 語法,確保自動關(guān)閉(觸發(fā)未完成子任務(wù)中斷);手動關(guān)閉需調(diào)用 shutdown(),但仍建議配合 try-with-resources;
  • 核心 scope 實(shí)現(xiàn):
  • 線程模型:fork() 方法默認(rèn)使用 ForkJoinPool.commonPool()(平臺線程),若要使用虛擬線程,需顯式指定線程工廠:scope.fork(() -> {...}, Thread.ofVirtual().factory());
  • 異常處理:
    • 取消機(jī)制:shutdown() 僅標(biāo)記 scope 為關(guān)閉狀態(tài),子任務(wù)需通過捕獲 InterruptedException 響應(yīng)取消(如場景 3 的子任務(wù) 5)。
    • ShutdownOnSuccess:任一子任務(wù)成功則立即關(guān)閉其他任務(wù),優(yōu)先返回首個成功結(jié)果;
    • ShutdownOnFailure:任一子任務(wù)失敗則立即關(guān)閉其他任務(wù),失敗信息存入 failures();
    • StructuredTaskScope:基礎(chǔ)實(shí)現(xiàn),需手動控制關(guān)閉 / 取消,靈活性最高;
  • join() 可能拋出 InterruptedException(線程中斷)、ExecutionException(子任務(wù)異常封裝);
  • 所有子任務(wù)的原始異常需通過 scope.failures() 獲取,而非直接捕獲 join() 的異常;

3. 向量 API(Vector API,JEP 448)—— 提升數(shù)值計(jì)算性能

3.1 特性說明

向量 API 是 JDK21 的孵化特性(Incubator)(經(jīng) JDK16-JDK20 多輪孵化優(yōu)化),旨在提供一套高效的數(shù)值計(jì)算 API,充分利用 CPU 的向量指令(如 AVX2、AVX512、NEON),實(shí)現(xiàn)單指令多數(shù)據(jù)(SIMD)并行計(jì)算,大幅提升數(shù)組、矩陣等數(shù)值操作的性能(尤其適合科學(xué)計(jì)算、機(jī)器學(xué)習(xí)、信號處理等場景)。它提供類型安全的向量操作,避免手動編寫匯編代碼,同時支持跨平臺,無需關(guān)注底層 CPU 架構(gòu)差異。
核心優(yōu)勢:

  • 高性能:直接映射 CPU 向量指令,SIMD 并行計(jì)算,比傳統(tǒng)循環(huán)快數(shù)倍(大規(guī)模計(jì)算場景);
  • 類型安全:強(qiáng)類型向量接口,編譯時檢查操作合法性,避免類型錯誤;
  • 跨平臺:自動適配 x86、ARM 等不同 CPU 架構(gòu),無需修改代碼;
  • 易用性:API 設(shè)計(jì)簡潔,支持向量加減乘除、邏輯運(yùn)算、聚合等常用操作;
  • 自適應(yīng):支持 SPECIES_PREFERRED 自動適配當(dāng)前 CPU 最優(yōu)向量長度。

3.2 代碼樣例(向量計(jì)算 + 性能對比)

import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorSpecies;
import java.util.Arrays;
/**
 * 向量API(孵化特性)演示 + 性能對比
 * 編譯命令:javac --release 21 --add-modules jdk.incubator.vector VectorAPIDemo.java
 * 運(yùn)行命令:java --add-modules jdk.incubator.vector VectorAPIDemo
 */
public class VectorAPIDemo {
    // 定義向量物種:自動適配當(dāng)前CPU最優(yōu)長度(推薦),float類型
    private static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;
    // 也可手動指定:FloatVector.SPECIES_128(128位,4個float)、FloatVector.SPECIES_256(256位,8個float)
    // 傳統(tǒng)循環(huán)計(jì)算:兩個float數(shù)組相加
    public static void arrayAddTraditional(float[] a, float[] b, float[] result) {
        for (int i = 0; i < a.length; i++) {
            result[i] = a[i] + b[i];
        }
    }
    // 向量API計(jì)算:兩個float數(shù)組相加(修正length()為length)
    public static void arrayAddVector(float[] a, float[] b, float[] result) {
        int i = 0;
        // 向量批量處理(每次處理SPECIES.length個元素)
        int upperBound = SPECIES.loopBound(a.length);
        for (; i < upperBound; i += SPECIES.length) { // 修正:length(屬性)而非length()
            // 從數(shù)組中加載向量
            FloatVector va = FloatVector.fromArray(SPECIES, a, i);
            FloatVector vb = FloatVector.fromArray(SPECIES, b, i);
            // 向量相加,結(jié)果存儲到數(shù)組
            va.add(vb).intoArray(result, i);
        }
        // 處理剩余不足一個向量長度的元素
        for (; i < a.length; i++) {
            result[i] = a[i] + b[i];
        }
    }
    public static void main(String[] args) {
        // 初始化兩個大數(shù)組(1000萬元素)
        int size = 10_000_000;
        float[] a = new float[size];
        float[] b = new float[size];
        float[] resultTraditional = new float[size];
        float[] resultVector = new float[size];
        // 填充數(shù)據(jù)(固定值,避免隨機(jī)數(shù)影響性能)
        Arrays.fill(a, 1.23f);
        Arrays.fill(b, 4.56f);
        // JIT預(yù)熱:先運(yùn)行一次,避免編譯開銷影響性能測試
        arrayAddTraditional(a, b, resultTraditional);
        arrayAddVector(a, b, resultVector);
        // 測試傳統(tǒng)循環(huán)性能(多次運(yùn)行取平均)
        long start = System.currentTimeMillis();
        for (int j = 0; j < 5; j++) {
            arrayAddTraditional(a, b, resultTraditional);
        }
        long traditionalTime = (System.currentTimeMillis() - start) / 5;
        System.out.println("傳統(tǒng)循環(huán)平均耗時:" + traditionalTime + "ms");
        // 測試向量API性能(多次運(yùn)行取平均)
        start = System.currentTimeMillis();
        for (int j = 0; j < 5; j++) {
            arrayAddVector(a, b, resultVector);
        }
        long vectorTime = (System.currentTimeMillis() - start) / 5;
        System.out.println("向量API平均耗時:" + vectorTime + "ms");
        // 驗(yàn)證結(jié)果一致性
        boolean isEqual = Arrays.equals(resultTraditional, resultVector);
        System.out.println("結(jié)果是否一致:" + isEqual);
        // 打印向量物種信息(當(dāng)前CPU適配的長度)
        System.out.println("當(dāng)前CPU最優(yōu)向量長度(float元素?cái)?shù)):" + SPECIES.length);
    }
}

3.3 運(yùn)行結(jié)果

傳統(tǒng)循環(huán)平均耗時:30ms
向量API平均耗時:7ms
結(jié)果是否一致:true
當(dāng)前CPU最優(yōu)向量長度(float元素?cái)?shù)):8

3.4 注意事項(xiàng)

啟用方式(核心修正):

  • 編譯:javac --release 21 --add-modules jdk.incubator.vector VectorAPIDemo.java
  • 運(yùn)行:java --add-modules jdk.incubator.vector VectorAPIDemo;
  • 無需 --enable-preview(孵化特性≠預(yù)覽特性),需導(dǎo)入 jdk.incubator.vector 包。

向量物種選擇:

  • 優(yōu)先使用 SPECIES_PREFERRED(自動適配當(dāng)前 CPU 最優(yōu)向量長度);
  • 手動選擇需匹配 CPU 架構(gòu)(x86 支持 SPECIES_128/256/512,ARM 支持 SPECIES_128/256)。

適用場景:

  • 適合大規(guī)模數(shù)值計(jì)算(數(shù)組 / 矩陣運(yùn)算,元素?cái)?shù) ≥ 10 萬);
  • 小規(guī)模計(jì)算(<1 萬元素)因向量初始化開銷,性能可能不如傳統(tǒng)循環(huán)。

數(shù)據(jù)類型支持:僅支持 float、double、int、long 等基本數(shù)值類型,不支持引用類型。

性能優(yōu)化:

  • 數(shù)組長度盡量為向量長度的整數(shù)倍,減少剩余元素循環(huán);
  • 性能測試需做 JIT 預(yù)熱(先運(yùn)行幾次),避免編譯開銷導(dǎo)致數(shù)據(jù)失真;
  • 確保 CPU 開啟向量指令集(如 x86 的 AVX2/AVX512),否則性能無提升。

三、總結(jié)

JDK21 作為 LTS 版本,核心正式特性聚焦于提升開發(fā)效率、程序性能和代碼安全性,虛擬線程、模式匹配 for switch、記錄模式、密封類、分代 ZGC、序列化集合六大正式特性,可直接應(yīng)用于生產(chǎn)環(huán)境,尤其適合高并發(fā)、大數(shù)據(jù)、企業(yè)級應(yīng)用場景;五大預(yù)覽特性則為后續(xù)開發(fā)提供了更多可能性,可根據(jù)項(xiàng)目需求選擇性試用(需注意預(yù)覽特性可能在未來版本中調(diào)整)。

本文所有代碼均經(jīng)過 JDK21 環(huán)境測試,可直接復(fù)制運(yùn)行,建議開發(fā)者結(jié)合實(shí)際項(xiàng)目場景,合理運(yùn)用這些新特性,提升開發(fā)效率和程序性能。后續(xù)可持續(xù)關(guān)注 JDK 版本更新,及時掌握新特性的優(yōu)化和迭代。

到此這篇關(guān)于Java JDK21 新特性全面解析的文章就介紹到這了,更多相關(guān)Java JDK21 新特性內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java反轉(zhuǎn)鏈表的多種解決方法舉例詳解

    java反轉(zhuǎn)鏈表的多種解決方法舉例詳解

    這篇文章主要介紹了java反轉(zhuǎn)鏈表的多種解決方法,分別是使用棧、雙指針和遞歸,每種方法都有其實(shí)現(xiàn)原理和代碼示例,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-04-04
  • Spring?boot如何在IDEA中讓一個應(yīng)用在不同的端口多次啟動詳解

    Spring?boot如何在IDEA中讓一個應(yīng)用在不同的端口多次啟動詳解

    在開發(fā)過程中,SpringBoot項(xiàng)目的多端口啟動是一個實(shí)用的需求,特別是在進(jìn)行并發(fā)測試或者隔離環(huán)境時,這篇文章主要介紹了Spring?boot如何在IDEA中讓一個應(yīng)用在不同的端口多次啟動的相關(guān)資料,需要的朋友可以參考下
    2026-01-01
  • 淺析如何在Java應(yīng)用中優(yōu)雅的發(fā)送短信

    淺析如何在Java應(yīng)用中優(yōu)雅的發(fā)送短信

    很多業(yè)務(wù)場景里,我們都需要發(fā)送短信,比如登陸驗(yàn)證碼、告警、營銷通知、節(jié)日祝福等等,這篇文章,我們聊聊 Java 應(yīng)用中如何優(yōu)雅的發(fā)送短信,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下
    2023-11-11
  • SpringCloud-Alibaba-Sentinel服務(wù)降級,熱點(diǎn)限流,服務(wù)熔斷

    SpringCloud-Alibaba-Sentinel服務(wù)降級,熱點(diǎn)限流,服務(wù)熔斷

    這篇文章主要介紹了SpringCloud-Alibaba-Sentinel服務(wù)降級,熱點(diǎn)限流,服務(wù)熔斷,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • Spring?@Autowired注解超詳細(xì)示例

    Spring?@Autowired注解超詳細(xì)示例

    @Autowired注解可以用在類屬性,構(gòu)造函數(shù),setter方法和函數(shù)參數(shù)上,該注解可以準(zhǔn)確地控制bean在何處如何自動裝配的過程。在默認(rèn)情況下,該注解是類型驅(qū)動的注入
    2022-08-08
  • springboot+rabbitmq實(shí)現(xiàn)指定消費(fèi)者才能消費(fèi)的方法

    springboot+rabbitmq實(shí)現(xiàn)指定消費(fèi)者才能消費(fèi)的方法

    當(dāng)項(xiàng)目部署到測試環(huán)境后,QA測試過程中,總是“莫名其妙”的發(fā)現(xiàn)所保存的用戶付款單數(shù)據(jù)有問題。這篇文章主要介紹了springboot+rabbitmq實(shí)現(xiàn)指定消費(fèi)者才能消費(fèi),需要的朋友可以參考下
    2021-11-11
  • java高級應(yīng)用:線程池的全面講解(干貨)

    java高級應(yīng)用:線程池的全面講解(干貨)

    這篇文章主要介紹了java高級應(yīng)用:線程池的全面講解(干貨),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 淺談Java中Map和Set之間的關(guān)系(及Map.Entry)

    淺談Java中Map和Set之間的關(guān)系(及Map.Entry)

    這篇文章主要介紹了淺談Java中Map和Set之間的關(guān)系(及Map.Entry),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • Java中本地緩存的4種實(shí)現(xiàn)方式總結(jié)

    Java中本地緩存的4種實(shí)現(xiàn)方式總結(jié)

    這篇文章主要介紹了Java中本地緩存的4種實(shí)現(xiàn)方式,分別是基礎(chǔ)緩存實(shí)現(xiàn)、GuavaLoadingCache、SpringBoot整合Caffeine和JetCache,通過實(shí)例代碼,詳細(xì)講解了每種緩存技術(shù)的特點(diǎn)和使用方法,需要的朋友可以參考下
    2025-04-04
  • springboot一鍵application.yml配置文件實(shí)踐

    springboot一鍵application.yml配置文件實(shí)踐

    application-dev.yml文件是Spring Boot項(xiàng)目中用于定義開發(fā)環(huán)境配置的一個YAML格式文件,它包含了數(shù)據(jù)庫連接、服務(wù)器端口、日志級別、緩存配置等開發(fā)過程中常用的設(shè)置,通過這個文件,開發(fā)者可以在不同的環(huán)境中(如開發(fā)、測試、生產(chǎn))切換配置,而無需修改代碼
    2026-02-02

最新評論

景洪市| 广宁县| 神农架林区| 德安县| 乌苏市| 陵川县| 钟祥市| 晋江市| 瑞昌市| 炎陵县| 英德市| 诸城市| 梁平县| 霍城县| 海晏县| 彩票| 昆明市| 九台市| 朝阳县| 湘西| 西青区| 手机| 黔江区| 团风县| 固镇县| 临海市| 澄江县| 乃东县| 临安市| 秦安县| 舟曲县| 电白县| 高阳县| 旬阳县| 平顶山市| 海林市| 龙陵县| 凉城县| 淮阳县| 三都| 朝阳县|