JDK 18 新特性详解
· 阅读需 7 分钟
Java 18 作为一个非长期支持版本(non-LTS),于2022年3月22日正式发布。这个版本带来了一些实用的新特性和改进,让我们一起来了解这些新特性。
1. UTF-8 默认字符集
JDK 18 将 UTF-8 设置为所有 Java API 的默认字符集:
// 在 JDK 18 之前
System.out.println(Charset.defaultCharset()); // 可能输出 windows-1252、GBK 等
// 在 JDK 18 中
System.out.println(Charset.defaultCharset()); // 始终输出 UTF-8
主要优点:
- 跨平台一致性
- 简化国际化开发
- 减少字符编码问题
- 提高代码可移植性
2. 简单的 Web 服务器
引入了一个简单的命令行工具来启动 Web 服务器:
// 命令行启动
// jwebserver -p 8000 -d /path/to/directory
// 使用 API 启动服务器
import com.sun.net.httpserver.*;
public class SimpleWebServerExample {
public static void main(String[] args) throws IOException {
SimpleFileServer.createFileServer(
new InetSocketAddress(8080),
Path.of("/path/to/directory"),
SimpleFileServer.OutputLevel.VERBOSE
).start();
// 自定义处理器
HttpServer server = HttpServer.create(
new InetSocketAddress(8080), 0);
server.createContext("/api", exchange -> {
String response = "{\"message\": \"Hello, World!\"}";
exchange.getResponseHeaders().set("Content-Type", "application/json");
exchange.sendResponseHeaders(200, response.length());
try (OutputStream os = exchange.getResponseBody()) {
os.write(response.getBytes());
}
});
server.start();
}
}
特点:
- 快速启动静态文件服务
- 支持 HTTP/1.1
- 可编程 API
- 适合开发和测试
3. 代码片段(Code Snippets)
Java API 文档中支持代码片段:
/**
* 计算两个数的和。
*
* {@snippet :
* int result = calculator.add(5, 3);
* System.out.println(result); // 输出: 8
* }
*/
public int add(int a, int b) {
return a + b;
}
/**
* 使用新的文件 API。
*
* {@snippet file="FileExample.java" region="read-file"}
*/
public class FileExample {
// @start region="read-file"
public String readFile(Path path) throws IOException {
return Files.readString(path);
}
// @end
}
改进:
- 更好的文档示例
- 支持语法高亮
- 可验证的代码片段
- 提升文档质量
4. 模式匹配 Switch(第二次预览)
Switch 模式匹配的改进版本:
public String formatValue(Object obj) {
return switch (obj) {
case Integer i when i > 0 ->
String.format("正整数:%d", i);
case Integer i ->
String.format("整数:%d", i);
case Double d when d > 0 ->
String.format("正小数:%.2f", d);
case Double d ->
String.format("小数:%.2f", d);
case String s when s.length() > 0 ->
String.format("非空字符串:%s", s);
case String s ->
"空字符串";
case null ->
"空值";
default ->
obj.toString();
};
}
新特性:
- 支持守卫表达式
- null 处理改进
- 更好的类型推断
- 增强的模式匹配
5. 向量 API(第三次孵化)
向量 API 的进一步改进:
// 向量计算示例
public class VectorExample {
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;
public static void vectorComputation(float[] a, float[] b, float[] c) {
int i = 0;
int upperBound = SPECIES.loopBound(a.length);
// 向量化循环
for (; i < upperBound; i += SPECIES.length()) {
var va = FloatVector.fromArray(SPECIES, a, i);
var vb = FloatVector.fromArray(SPECIES, b, i);
var vc = va.mul(vb);
vc.intoArray(c, i);
}
// 处理剩余元素
for (; i < a.length; i++) {
c[i] = a[i] * b[i];
}
}
// SIMD 操作示例
public static void simdOperation(float[] array) {
var species = FloatVector.SPECIES_256;
var vector = FloatVector.fromArray(species, array, 0);
// 数学运算
var result = vector
.mul(2.0f) // 乘法
.add(1.0f) // 加法
.abs() // 绝对值
.sqrt(); // 平方根
result.intoArray(array, 0);
}
}
改进:
- 性能优化
- 更多平台支持
- API 完善
- 更好的编译器优化
6. 互联网地址解析 SPI
新增了互联网地址解析的服务提供者接口:
// 自定义解析器
public class CustomInetAddressResolver implements InetAddressResolver {
@Override
public InetAddress[] resolve(String host) throws UnknownHostException {
// 实现自定义解析逻辑
if ("custom.domain".equals(host)) {
return new InetAddress[] {
InetAddress.getByAddress(
host,
new byte[] {127, 0, 0, 1}
)
};
}
throw new UnknownHostException(host);
}
@Override
public String getHostByAddr(byte[] addr) throws UnknownHostException {
// 实现反向解析
return InetAddress.getByAddress(addr).getHostName();
}
}
// 使用自定义解析器
public class AddressResolutionExample {
public static void main(String[] args) throws Exception {
InetAddress address = InetAddress.getByName("custom.domain");
System.out.println(address.getHostAddress());
// 配置解析器
System.setProperty(
"jdk.net.hosts.file",
"/path/to/custom/hosts"
);
}
}
特点:
- 可自定义解析逻辑
- 支持本地缓存
- 灵活的配置选项
- 改进的可测试性
7. 废弃终结器
开始废弃终结器(Finalizer):
// 不推荐使用终结器
public class DeprecatedFinalizerExample {
@Deprecated(since="18", forRemoval=true)
@Override
protected void finalize() throws Throwable {
try {
// 清理代码
} finally {
super.finalize();
}
}
// 推荐使用 Cleaner
public class CleanerExample implements AutoCloseable {
private static final Cleaner cleaner = Cleaner.create();
private final CleaningAction cleaningAction;
private final Cleaner.Cleanable cleanable;
public CleanerExample() {
this.cleaningAction = new CleaningAction();
this.cleanable = cleaner.register(this, cleaningAction);
}
@Override
public void close() {
cleanable.clean();
}
private static class CleaningAction implements Runnable {
@Override
public void run() {
// 执行清理操作
}
}
}
}
建议:
- 使用 try-with-resources
- 采用 Cleaner 机制
- 显式资源管理
- 避免依赖终结器
总结
JDK 18 虽然是一个非 LTS 版本,但它带来了一些实用的改进。UTF-8 默认字符集的变更和简单 Web 服务器的引入都是非常实用的特性,可以提高开发效率。同时,代码片段的支持改进了文档质量,而模式匹配 Switch 和向量 API 的持续改进也显示了 Java 在语言特性和性能优化方面的努力。
对于开发者来说,建议:
- 使用 UTF-8 作为默认字符集
- 利用简单 Web 服务器进行快速原型开发
- 在文档中使用新的代码片段特性
- 关注模式匹配和向量 API 的发展
- 开始规划终结器的替代方案
虽然这是一个过渡版本,但其中的一些特性为未来的 Java 发展奠定了基础,值得开发者关注和学习。