新聞中心
?Java 19 在2022 年 9 月 20 日正式發(fā)布,Java 19 不是一個(gè)長(zhǎng)期支持版本,直到 2023 年 3 月它將被 JDK 20 取代,這次更新共帶來(lái) 7 個(gè)新功能。

bin ./java -version
openjdk version "19" 2022-09-20
OpenJDK Runtime Environment (build 19+36-2238)
OpenJDK 64-Bit Server VM (build 19+36-2238, mixed mode, sharing)
OpenJDK Java 19 下載:https://jdk.java.net/19/
OpenJDK Java 19 文檔:https://openjdk.java.net/projects/jdk/19/
Java 19 帶來(lái)的 7 個(gè)新特性:
|
JEP |
描述 |
|
405 |
Record 模式匹配 (Preview) |
|
425 |
虛擬線(xiàn)程 (預(yù)覽) |
|
427 |
Switch 模式匹配 (三次預(yù)覽) |
|
422 |
Linux/RISC-V Port |
|
426 |
Vector API (四次孵化) |
|
424 |
外部函數(shù) & 內(nèi)存 API (Preview) |
|
428 |
Structured Concurrency (Incubator) |
Java 19 新功能介紹是 Java 新特性系列文章中的一部分。系列詳情可以瀏覽:https://www.wdbyte.com/java-feature/
JEP 405: Record 模式匹配(預(yù)覽)
record? 是一種全新的類(lèi)型,它本質(zhì)上是一個(gè) final? 類(lèi),同時(shí)所有的屬性都是 final? 修飾,它會(huì)自動(dòng)編譯出 public get hashcode? 、equals、toString 等方法,減少了代碼編寫(xiě)量。Record 在 Java 14 中被提出,在 Java 15 中二次預(yù)覽,在 Java 16 中正式發(fā)布。
示例:編寫(xiě)一個(gè) Dog record 類(lèi),定義 name 和 age 屬性。
package com.wdbyte;
public record Dog(String name, Integer age) {
}
Record 的使用。
package com.wdbyte;
public class Java14Record {
public static void main(String[] args) {
Dog dog1 = new Dog("牧羊犬", 1);
Dog dog2 = new Dog("田園犬", 2);
Dog dog3 = new Dog("哈士奇", 3);
System.out.println(dog1);
System.out.println(dog2);
System.out.println(dog3);
}
}
輸出結(jié)果:
Dog[name=牧羊犬, age=1]
Dog[name=田園犬, age=2]
Dog[name=哈士奇, age=3]
在 Java 19 中,為 Record 帶來(lái)了增強(qiáng)的模式匹配,在使用 instanceof 后,可以進(jìn)行類(lèi)型轉(zhuǎn)換。
public class RecordTest {
public static void main(String[] args) {
Object dog1 = new Dog("牧羊犬", 1);
if(dog1 instanceof Dog dogTemp){
System.out.println(dogTemp.name());
}
}
}
record Dog( String name, Integer age ){
}甚至可以在使用 instanceof? 時(shí)直接得到 Record 中的變量引用。
public class RecordTest2 {
public static void main(String[] args) {
Object dog1 = new Dog("牧羊犬", 1);
if(dog1 instanceof Dog(String name,Integer age)){
System.out.println(name+":"+age);
}
}
}
record Dog( String name, Integer age ){
}擴(kuò)展:
Java 14 instanceof 類(lèi)型推斷
Java 16 Record 介紹
JEP 425: 虛擬線(xiàn)程 (預(yù)覽)
很實(shí)用的一個(gè)新特性,從 Java 19 開(kāi)始逐步的引入虛擬線(xiàn)程,虛擬線(xiàn)程是輕量級(jí)的線(xiàn)程,可以在顯著的減少代碼的編寫(xiě),提高可維護(hù)性的同時(shí)提高系統(tǒng)的吞吐量。
引入的原因
一直以來(lái),在 Java 并發(fā)編程中,Thread 都是十分重要的一部分,Thread 是 Java 中的并發(fā)單元,每個(gè) Thread 線(xiàn)程都提供了一個(gè)堆棧來(lái)存儲(chǔ)局部變量和方法調(diào)用,以及線(xiàn)程上下文等相關(guān)信息。
但問(wèn)題是線(xiàn)程和進(jìn)程一樣,都是一項(xiàng)昂貴的資源,JDK 將 Thread 線(xiàn)程實(shí)現(xiàn)為操作系統(tǒng)線(xiàn)程的包裝器,也就是說(shuō)成本很高,而且數(shù)量有限。也因此我們會(huì)使用線(xiàn)程池來(lái)管理線(xiàn)程,同時(shí)限制線(xiàn)程的數(shù)量。比如常用的 Tomcat 會(huì)為每次請(qǐng)求單獨(dú)使用一個(gè)線(xiàn)程進(jìn)行請(qǐng)求處理,同時(shí)限制處理請(qǐng)求的線(xiàn)程數(shù)量以防止線(xiàn)程過(guò)多而崩潰;這很有可能在 CPU 或網(wǎng)絡(luò)連接沒(méi)有耗盡之前,線(xiàn)程數(shù)量已經(jīng)耗盡,從而限制了 web 服務(wù)的吞吐量。
看到這里你可能要說(shuō)了,可以放棄請(qǐng)求和線(xiàn)程一一對(duì)應(yīng)的方式啊,使用異步編程來(lái)解決這個(gè)問(wèn)題,把請(qǐng)求處理分段,在組合成順序管道,通過(guò)一套 API 進(jìn)行管理,這樣就可以使用有限的線(xiàn)程來(lái)處理超過(guò)線(xiàn)程數(shù)量的請(qǐng)求。這當(dāng)然也是可以的,但是隨之而來(lái)的問(wèn)題是:
- 需要額外的學(xué)習(xí)異步編程。
- 代碼復(fù)雜度增加,等于放棄了語(yǔ)言的基本順序組合運(yùn)算。
- 堆棧上下文信息都變得難以追蹤。
- Debug 困難。
- 和 Java 平臺(tái)本身的編程風(fēng)格有沖突,Java 并發(fā)單元是 Thread,而這時(shí)是異步管道。
虛擬線(xiàn)程
基于上面的種種原因,Java 19 引入了虛擬線(xiàn)程,在使用體驗(yàn)上和 Thread 沒(méi)有區(qū)別,與之前的 API 互相兼容,但是相比之下虛擬線(xiàn)程資源占用非常少,同時(shí)優(yōu)化了硬件的使用效率,因此非常易用且不需要被池化。
下面是一個(gè)示例,創(chuàng)建 10 萬(wàn)個(gè)線(xiàn)程,然后都休眠 1 秒鐘最后打印耗時(shí),如果是開(kāi)傳統(tǒng)的 Thread 線(xiàn)程的方式,資源十分緊張;如果是線(xiàn)程池的方式,必定有部分線(xiàn)程在等待線(xiàn)程釋放;但是使用虛擬線(xiàn)程的方式,可以瞬間完成。
import java.util.concurrent.Executors;
import java.util.stream.IntStream;
public class ThreadTest {
public static void main(String[] args) {
long start = System.currentTimeMillis();
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 100_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(1000);
return i;
});
});
}
System.out.println("耗時(shí):" + (System.currentTimeMillis() - start)+"ms");
}
}
執(zhí)行后發(fā)現(xiàn) 1.3 秒執(zhí)行完畢,速度驚人。
bin ./java --enable-preview --source 19 ThreadTest.java
注: ThreadTest.java 使用 Java SE 19 的預(yù)覽功能。
注: 有關(guān)詳細(xì)信息,請(qǐng)使用 -Xlint:preview 重新編譯。
耗時(shí):1309ms
bin
注意:虛擬線(xiàn)程只是增加程序的吞吐量,并不能提高程序的處理速度。
JEP 427: switch 模式匹配 (三次預(yù)覽)
Switch 模式匹配在 Java 17 中已經(jīng)引入,在 Java 18 中二次預(yù)覽,現(xiàn)在在 Java 19 中進(jìn)行三次預(yù)覽,功能和在 Java 18 新功能介紹 - Switch 中介紹的一樣,改進(jìn)后的 Switch 模式匹配可以代碼更加簡(jiǎn)潔,邏輯更加清晰,下面是一些使用示例對(duì)比。
下面是幾個(gè)例子:
static String formatter(Object o) {
String formatted = "unknown";
if (o instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (o instanceof Long l) {
formatted = String.format("long %d", l);
} else if (o instanceof Double d) {
formatted = String.format("double %f", d);
} else if (o instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}而在 Java 17 之后,可以通過(guò)下面的寫(xiě)法進(jìn)行改進(jìn):
static String formatterPatternSwitch(Object o) {
return switch (o) {
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 -> o.toString();
};
}switch 可以和 null 進(jìn)行結(jié)合判斷:
static void testFooBar(String s) {
switch (s) {
case null -> System.out.println("Oops");
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}case 時(shí)可以加入復(fù)雜表達(dá)式:
static void testTriangle(Shape s) {
switch (s) {
case Triangle t && (t.calculateArea() > 100) ->
System.out.println("Large triangle");
default ->
System.out.println("A shape, possibly a small triangle");
}
}case 時(shí)可以進(jìn)行類(lèi)型判斷:
sealed interface S permits A, B, C {}
final class A implements S {}
final class B implements S {}
record C(int i) implements S {} // Implicitly final
static int testSealedExhaustive(S s) {
return switch (s) {
case A a -> 1;
case B b -> 2;
case C c -> 3;
};
}擴(kuò)展:JEP 406:Switch 的類(lèi)型匹配(預(yù)覽)
JEP 422: Linux/RISC-V Port
RISC-V是一個(gè)免費(fèi)和開(kāi)源的 RISC 指令集架構(gòu) (ISA),實(shí)際上 RISC-V 是一系列相關(guān)的 ISA,現(xiàn)在 Java 19 開(kāi)始對(duì)其進(jìn)行支持。
JEP 424: 外部函數(shù) & 內(nèi)存 API (預(yù)覽)
此功能引入的 API 允許 Java 開(kāi)發(fā)者與 JVM 之外的代碼和數(shù)據(jù)進(jìn)行交互,通過(guò)調(diào)用外部函數(shù)(JVM之外)和安全的訪問(wèn)外部?jī)?nèi)存(非 JVM 管理),讓 Java 程序可以調(diào)用本機(jī)庫(kù)并處理本機(jī)數(shù)據(jù),而不會(huì)像 JNI 一樣存在很多安全風(fēng)險(xiǎn)。
這不是一個(gè)新功能,自 Java 14 就已經(jīng)引入,此次對(duì)其進(jìn)行了性能、通用性、安全性、易用性上的優(yōu)化。
歷史
- Java 14JEP 370 引入了外部?jī)?nèi)存訪問(wèn) API(孵化器)。
- Java 15JEP 383引入了外部?jī)?nèi)存訪問(wèn) API(第二孵化器)。
- Java 16JEP 389引入了外部鏈接器 API(孵化器)。
- Java 16JEP 393引入了外部?jī)?nèi)存訪問(wèn) API(第三孵化器)。
- Java 17JEP 412引入了外部函數(shù)和內(nèi)存 API(孵化器)。
- Java 18JEP 419引入了外部函數(shù)和內(nèi)存 API(二次孵化器)。
其他更新
JEP 426: Vector API (四次孵化)
通過(guò)將在運(yùn)行時(shí)可靠地編譯為支持的 CPU 架構(gòu)上的向量指令的向量計(jì)算表示,與等效的標(biāo)量計(jì)算相比,實(shí)現(xiàn)了卓越的性能。此功能已經(jīng)第四次孵化,在之前 Java 16 ~ Java 18 中都有介紹,這里不做贅述。
JEP 428: Structured Concurrency (孵化)
通過(guò)簡(jiǎn)化多線(xiàn)程編程并將在不同線(xiàn)程中運(yùn)行的多個(gè)任務(wù)視為單個(gè)工作單元,簡(jiǎn)化錯(cuò)誤處理和取消,提高可靠性并增強(qiáng)可觀察性。
標(biāo)題名稱(chēng):聊聊 Java 19 新功能,你學(xué)會(huì)了嗎?
分享URL:http://www.dlmjj.cn/article/dpedshd.html


咨詢(xún)
建站咨詢(xún)
