文章目录
- 一、Java 18 新特性
- 1.1、UTF-8 作为默认字符集(JEP 400)
- 1.2、简易 Web 服务器(JEP 408)
- 1.3、代码片段标签 `@snippet`(JEP 413)
- 1.4、使用方法句柄重新实现反射核心(JEP 416)
- 1.5、向量 API(JEP 417,第三次孵化)
- 1.6、Internet-Address 解析 SPI(JEP 418)
- 1.7、外部函数与内存 API(JEP 419,第二次孵化)
- 1.8、模式匹配增强(JEP 420,第二次预览)
- 1.9、废弃 Finalization(JEP 421)
- 二、Java 19 新特性
- 2.1、记录模式(预览 JEP 405)
- 2.2、Linux/RISC-V Port 端口(JEP 422)
- 2.3、外部函数 & 内存 API(预览 JEP 424)
- 2.4、虚拟线程(预览 JEP 425)
- 2.5、Vector API(第四次孵化 JEP 426)
- 2.6、switch的模式匹配(第三次预览 JEP 427)
- 2.7、结构化并发(孵化器 JEP 428)
- 三、Java 20 新特性
- 3.1、作用域值(Scoped Values,孵化器 JEP 429)
- 3.2、记录模式(Record Patterns,第二预览 JEP 432)
- 3.3、switch 模式匹配(第四预览 JEP 433)
- 3.4、外部函数 & 内存 API(第二预览 JEP 434)
- 3.5、虚拟线程(第二预览 JEP 436)
- 3.6、结构化并发(第二孵化器 JEP 437)
- 3.7、向量 API(第五孵化器 JEP 438)
- 四、参考
一、Java 18 新特性
官网:https://openjdk.org/projects/jdk/18/
Java 18 在 2022 年 3 月 22 日正式发布,非长期支持版本。
Java 18 带来了 9 个新特性:
- JEP 400:UTF-8 by Default(默认字符集为 UTF-8)
- JEP 408:Simple Web Server(简易的 Web 服务器)
- JEP 413:Code Snippets in Java API Documentation(Java API 文档中的代码片段)
- JEP 416:Reimplement Core Reflection with Method Handles(使用方法句柄重新实现反射核心)
- JEP 417:Vector(向量) API(第三次孵化)
- JEP 418:Internet-Address Resolution(互联网地址解析)SPI
- JEP 419:Foreign Function & Memory API(外部函数和内存 API)(第二次孵化)
- JEP 420:Pattern Matching for switch(switch 模式匹配)(第二次预览)
- JEP 421:Deprecate Finalization for Removal(弃用 Finalization for Removal)
1.1、UTF-8 作为默认字符集(JEP 400)
所有 Java API 默认使用 UTF-8 字符集,避免因系统区域设置不同导致的问题。
import java.nio.charset.Charset;
public class CharsetDemo {
public static void main(String[] args) {
// 在 Java 18 中始终输出 UTF-8
System.out.println("默认字符集: " + Charset.defaultCharset().name());
}
}
1.2、简易 Web 服务器(JEP 408)
通过命令行或 API 快速启动一个静态文件服务器。
import com.sun.net.httpserver.SimpleFileServer;
import java.net.InetSocketAddress;
import java.nio.file.Path;
public class WebServerDemo {
public static void main(String[] args) throws Exception {
// 启动服务器,监听 8080 端口,服务当前目录的文件
var server = SimpleFileServer.createFileServer(
new InetSocketAddress(8080),
Path.of("."),
SimpleFileServer.OutputLevel.VERBOSE
);
server.start();
System.out.println("服务器已启动: http://localhost:8080");
}
}
1.3、代码片段标签 @snippet
(JEP 413)
在 Javadoc 中嵌入高亮代码示例,效果更好且使用起来更方便一些!
/
* 计算两数之和:
* {@snippet :
* int a = 10;
* int b = 20;
* int sum = a + b; // 高亮此行
* }
*/
public class Calculator {
public int add(int a, int b) { return a + b; }
}
1.4、使用方法句柄重新实现反射核心(JEP 416)
Java 18 改进了 java.lang.reflect.Method
、Constructor
的实现逻辑,使之性能更好,速度更快。这项改动不会改动相关 API ,这意味着开发中不需要改动反射相关代码,就可以体验到性能更好反射。
OpenJDK 官方给出了新老实现的反射性能基准测试结果。
1.5、向量 API(JEP 417,第三次孵化)
向量(Vector) API 最初由 JEP 338 提出,并作为孵化 API集成到 Java 16 中。第二轮孵化由 JEP 414 提出并集成到 Java 17 中,第三轮孵化由 JEP 417 提出并集成到 Java 18 中,第四轮由 JEP 426 提出并集成到了 Java 19 中。
向量计算由对向量的一系列操作组成。向量 API 用来表达向量计算,该计算可以在运行时可靠地编译为支持的 CPU 架构上的最佳向量指令,从而实现优于等效标量计算的性能。
向量 API 的目标是为用户提供简洁易用且与平台无关的表达范围广泛的向量计算。
import jdk.incubator.vector.*;
public class VectorDemo {
public static void main(String[] args) {
var a = IntVector.fromArray(IntVector.SPECIES_128, new int[]{1, 2, 3, 4}, 0);
var b = IntVector.fromArray(IntVector.SPECIES_128, new int[]{5, 6, 7, 8}, 0);
var c = a.add(b); // 并行计算四个整数的和
System.out.println("结果: " + Arrays.toString(c.toArray())); // [6, 8, 10, 12]
}
}
1.6、Internet-Address 解析 SPI(JEP 418)
自定义域名和地址的解析逻辑。
import java.net.spi.InetAddressResolver;
import java.net.spi.InetAddressResolverProvider;
// 实现自定义解析器(需在 META-INF/services 中注册)
public class MyResolverProvider extends InetAddressResolverProvider {
@Override
public InetAddressResolver get(Configuration configuration) {
return new CustomResolver();
}
// 其他方法省略...
}
1.7、外部函数与内存 API(JEP 419,第二次孵化)
安全地调用本地代码和管理堆外内存。
Java 程序可以通过该 API 与 Java 运行时之外的代码和数据进行互操作。通过高效地调用外部函数(即 JVM 之外的代码)和安全地访问外部内存(即不受 JVM 管理的内存),该 API 使 Java 程序能够调用本机库并处理本机数据,而不会像 JNI 那样危险和脆弱。
外部函数和内存 API 在 Java 17 中进行了第一轮孵化,由 JEP 412 提出。第二轮孵化由JEP 419 提出并集成到了 Java 18 中,预览由 JEP 424 提出并集成到了 Java 19 中。
import jdk.incubator.foreign.*;
public class ForeignMemoryDemo {
public static void main(String[] args) {
// 分配 100 字节的堆外内存
try (MemorySegment segment = MemorySegment.allocateNative(100)) {
segment.asByteBuffer().put((byte) 42);
System.out.println("写入的值: " + segment.asByteBuffer().get(0));
}
}
}
1.8、模式匹配增强(JEP 420,第二次预览)
switch
表达式支持更复杂的模式匹配和 null
处理(需启用 --enable-preview
)。
public class SwitchDemo {
public static void main(String[] args) {
Object obj = null;
String result = switch (obj) {
case Integer i -> "整数: " + i;
case String s && s.length() > 5 -> "长字符串: " + s;
case String s -> "短字符串: " + s;
case null -> "对象为 null";
default -> "未知类型";
};
System.out.println(result); // 输出: 对象为 null
}
}
1.9、废弃 Finalization(JEP 421)
标记 Object.finalize()
为过时,推荐使用 <font style="color:rgb(64, 64, 64);">Cleaner</font>
或 <font style="color:rgb(64, 64, 64);">try-with-resources</font>
管理资源。
import java.lang.ref.Cleaner;
public class ResourceCleanerDemo {
private static final Cleaner cleaner = Cleaner.create();
private static class Resource implements Runnable {
@Override
public void run() {
System.out.println("资源已清理");
}
}
public static void main(String[] args) {
Resource resource = new Resource();
cleaner.register(resource, resource); // 注册清理动作
}
}
Java 18通过强制UTF-8编码解决了跨平台乱码顽疾,jwebserver成为快速原型开发利器,@snippet标签革新了API文档编写方式,反射性能飞跃赋能主流框架,向量API开启硬件加速计算新时代。建议开发者在数据处理密集型和跨平台项目中优先采用这些特性。
二、Java 19 新特性
官网:https://openjdk.org/projects/jdk/19/
JDK 19 定于 2022 年 9 月 20 日正式发布以供生产使用,非长期支持版本。不过,JDK 19 中有一些比较重要的新特性值得关注。
JDK 19 只有 7 个新特性:
- JEP 405: Record Patterns(记录模式)(预览)
- JEP 422: Linux/RISC-V Port 端口
- JEP 424: Foreign Function & Memory API(外部函数和内存 API)(预览)
- JEP 425: Virtual Threads(虚拟线程)(预览)
- JEP 426: Vector(向量)API(第四次孵化)
- JEP 427: Pattern Matching for switch(switch 模式匹配)
- JEP 428: Structured Concurrency(结构化并发)(孵化)
2.1、记录模式(预览 JEP 405)
用模式匹配解构 Record 对象。
- 扩展模式匹配以解构记录类的实例,实现更复杂的数据查询
- 添加嵌套模式,实现更可组合的数据查询
record Point(int x, int y) {}
// instanceof 模式匹配
if (obj instanceof Point(int x, int y)) {
System.out.println(x + ", " + y);
}
// Switch 模式匹配
switch (obj) {
case Point(int x, int y) when x == y ->
System.out.println("点在对角线上");
case Point(int x, int y) ->
System.out.println("坐标: " + x + ", " + y);
default -> throw new IllegalArgumentException();
}
2.2、Linux/RISC-V Port 端口(JEP 422)
支持 RISC-V 开源指令集架构。
2.3、外部函数 & 内存 API(预览 JEP 424)
安全调用本地代码(如 C 库)。
Java 程序可以通过该 API 与 Java 运行时之外的代码和数据进行互操作。通过高效地调用外部函数(即 JVM 之外的代码)和安全地访问外部内存(即不受 JVM 管理的内存),该 API 使 Java 程序能够调用本机库并处理本机数据,而不会像 JNI 那样危险和脆弱。
外部函数和内存 API 在 Java 17 中进行了第一轮孵化,由 JEP 412 提出。第二轮孵化由JEP 419 提出并集成到了 Java 18 中,预览由 JEP 424 提出并集成到了 Java 19 中。
// 调用 C 的 sqrt 函数
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MethodHandle sqrt = linker.downcallHandle(
stdlib.find("sqrt").get(),
FunctionDescriptor.of(ValueLayout.JAVA_DOUBLE, ValueLayout.JAVA_DOUBLE)
);
double result = (double) sqrt.invokeExact(4.0);
System.out.println(result); // 输出 2.0
2.4、虚拟线程(预览 JEP 425)
轻量级线程,提高并发性能。
虚拟线程(Virtual Thread-)是 JDK 而不是 OS 实现的轻量级线程(Lightweight Process,LWP),许多虚拟线程共享同一个操作系统线程,虚拟线程的数量可以远大于操作系统线程的数量。
虚拟线程在其他多线程语言中已经被证实是十分有用的,比如 Go 中的 Goroutine、Erlang 中的进程。
虚拟线程避免了上下文切换的额外耗费,兼顾了多线程的优点,简化了高并发程序的复杂,可以有效减少编写、维护和观察高吞吐量并发应用程序的工作量。
知乎有一个关于 Java 19 虚拟线程的讨论,感兴趣的可以去看看:https://www.zhihu.com/question/536743167
Java 虚拟线程的详细解读和原理可以看下面文章:
- 虚拟线程原理及性能分析|得物技术
- Java19 正式 GA!看虚拟线程如何大幅提高系统吞吐量
- 虚拟线程 - VirtualThread 源码透视
// 创建虚拟线程
Thread.startVirtualThread(() -> {
System.out.println("Hello from virtual thread!");
});
// 使用 ExecutorService
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> downloadFile(url1));
executor.submit(() -> processData(url2));
}
2.5、Vector API(第四次孵化 JEP 426)
SIMD 并行计算加速。
IntVector a = IntVector.fromArray(IntVector.SPECIES_128, new int[]{1, 2, 3, 4}, 0);
IntVector b = IntVector.fromArray(IntVector.SPECIES_128, new int[]{5, 6, 7, 8}, 0);
IntVector c = a.add(b); // 并行执行 4 次加法
int[] resultArray = c.toArray(); // [6, 8, 10, 12]
2.6、switch的模式匹配(第三次预览 JEP 427)
扩展switch
表达式,支持类型匹配和条件判断:
Object obj = "Hello";
String result = switch (obj) {
case Integer i -> "Integer: " + i;
case String s when s.length() > 5 -> "Long String: " + s;
case String s -> "String: " + s;
default -> "Unknown";
};
通过case
后的类型匹配和when
子句的条件过滤,代码逻辑更清晰。
2.7、结构化并发(孵化器 JEP 428)
简化多线程任务管理,将子任务视为一个工作单元。
JDK 19 引入了结构化并发,一种多线程编程方法,目的是为了通过结构化并发 API 来简化多线程编程,并不是为了取代java.util.concurrent
,目前处于孵化器阶段。
结构化并发将不同线程中运行的多个任务视为单个工作单元,从而简化错误处理、提高可靠性并增强可观察性。也就是说,结构化并发保留了单线程代码的可读性、可维护性和可观察性。
结构化并发的基本 API 是StructuredTaskScope。StructuredTaskScope
支持将任务拆分为多个并发子任务,在它们自己的线程中执行,并且子任务必须在主任务继续之前完成。
// 需要添加 jdk.incubator.concurrent 模块
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> user = scope.fork(() -> getUserInfo());
Future<Integer> order = scope.fork(() -> getLatestOrder());
scope.join(); // 等待所有子任务
scope.throwIfFailed(); // 异常处理
System.out.println(user.resultNow() + ": " + order.resultNow());
}
三、Java 20 新特性
官网:https://openjdk.org/projects/jdk/20/
JDK 20 于 2023 年 3 月 21 日发布,非长期支持版本。
根据开发计划,下一个 LTS 版本就是将于 2023 年 9 月发布的 JDK 21。
JDK 20 只有 7 个新特性:
- JEP 429:Scoped Values(作用域值)(第一次孵化)
- JEP 432:Record Patterns(记录模式)(第二次预览)
- JEP 433:switch 模式匹配(第四次预览)
- JEP 434: Foreign Function & Memory API(外部函数和内存 API)(第二次预览)
- JEP 436: Virtual Threads(虚拟线程)(第二次预览)
- JEP 437:Structured Concurrency(结构化并发)(第二次孵化)
- JEP 432:向量 API(第五次孵化)
3.1、作用域值(Scoped Values,孵化器 JEP 429)
替代线程局部变量,提供更安全的不可变数据共享。
作用域值(Scoped Values)它可以在线程内和线程间共享不可变的数据,优于线程局部变量,尤其是在使用大量虚拟线程时。
// 需添加 jdk.incubator.concurrent 模块
final static ScopedValue<String> USER = ScopedValue.newInstance();
ScopedValue.where(USER, "Alice").run(() -> {
System.out.println(USER.get()); // 输出 Alice
});
3.2、记录模式(Record Patterns,第二预览 JEP 432)
支持嵌套记录解构和更复杂的模式匹配。
记录模式(Record Patterns) 可对 record 的值进行解构,也就是更方便地从记录类(Record Class)中提取数据。并且,还可以嵌套记录模式和类型模式结合使用,以实现强大的、声明性的和可组合的数据导航和处理形式。
注意:不要把记录模式和 JDK16 正式引入的记录类搞混了。
record Point(int x, int y) {}
record Line(Point start, Point end) {}
// 嵌套解构
if (obj instanceof Line(Point(int x1, int y1), Point(int x2, int y2))) {
System.out.println("线段端点: (" + x1 + "," + y1 + "), (" + x2 + "," + y2 + ")");
}
3.3、switch 模式匹配(第四预览 JEP 433)
在 switch
中直接解构对象并匹配条件。
正如 instanceof
一样, switch
也紧跟着增加了类型匹配自动转换功能。
Object obj = new Point(3, 3);
switch (obj) {
case Point(int x, int y) when x == y ->
System.out.println("点在对角线上");
case Point(int x, int y) ->
System.out.println("坐标: " + x + ", " + y);
default -> throw new IllegalArgumentException();
}
3.4、外部函数 & 内存 API(第二预览 JEP 434)
改进本地代码和内存操作的安全性。
JDK 20 中是第二次预览,由 JEP 434 提出,这次的改进包括:
MemorySegment
和MemoryAddress
抽象的统一- 增强的
MemoryLayout
层次结构 MemorySession
拆分为Arena
和SegmentScope
,以促进跨维护边界的段共享。
// 调用 C 的 strlen 函数
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MethodHandle strlen = linker.downcallHandle(
stdlib.find("strlen").get(),
FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)
);
try (Arena arena = Arena.openConfined()) {
MemorySegment str = arena.allocateUtf8String("Hello");
long len = (long) strlen.invokeExact(str);
System.out.println(len); // 输出 5
}
3.5、虚拟线程(第二预览 JEP 436)
轻量级线程的 API 优化。
虚拟线程(Virtual Thread)是 JDK 而不是 OS 实现的轻量级线程(Lightweight Process,LWP),由 JVM 调度。许多虚拟线程共享同一个操作系统线程,虚拟线程的数量可以远大于操作系统线程的数量。
在引入虚拟线程之前,java.lang.Thread
包已经支持所谓的平台线程,也就是没有虚拟线程之前,我们一直使用的线程。JVM 调度程序通过平台线程(载体线程)来管理虚拟线程,一个平台线程可以在不同的时间执行不同的虚拟线程(多个虚拟线程挂载在一个平台线程上),当虚拟线程被阻塞或等待时,平台线程可以切换到执行另一个虚拟线程。
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> {
System.out.println("虚拟线程执行任务");
});
}
3.6、结构化并发(第二孵化器 JEP 437)
简化多线程错误处理和取消操作。
Java 19 引入了结构化并发,一种多线程编程方法,目的是为了通过结构化并发 API 来简化多线程编程,并不是为了取代java.util.concurrent
,目前处于孵化器阶段。
结构化并发将不同线程中运行的多个任务视为单个工作单元,从而简化错误处理、提高可靠性并增强可观察性。也就是说,结构化并发保留了单线程代码的可读性、可维护性和可观察性。
结构化并发的基本 API 是StructuredTaskScope。StructuredTaskScope
支持将任务拆分为多个并发子任务,在它们自己的线程中执行,并且子任务必须在主任务继续之前完成。
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> task1 = scope.fork(() -> "结果1");
Future<String> task2 = scope.fork(() -> "结果2");
scope.join();
System.out.println(task1.resultNow() + " + " + task2.resultNow());
}
3.7、向量 API(第五孵化器 JEP 438)
向量计算由对向量的一系列操作组成。向量 API 用来表达向量计算,该计算可以在运行时可靠地编译为支持的 CPU 架构上的最佳向量指令,从而实现优于等效标量计算的性能。
向量 API 的目标是为用户提供简洁易用且与平台无关的表达范围广泛的向量计算。
向量(Vector) API 最初由 JEP 338 提出,并作为孵化 API集成到 Java 16 中。第二轮孵化由 JEP 414 提出并集成到 Java 17 中,第三轮孵化由 JEP 417 提出并集成到 Java 18 中,第四轮由 JEP 426 提出并集成到了 Java 19 中。
Java20 的这次孵化基本没有改变向量 API ,只是进行了一些错误修复和性能增强,详见 JEP 438。
四、参考
Java 18 新特性概览