跳到主要内容

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
java

主要优点:

  • 跨平台一致性
  • 简化国际化开发
  • 减少字符编码问题
  • 提高代码可移植性

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();
}
}
java

特点:

  • 快速启动静态文件服务
  • 支持 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
}
java

改进:

  • 更好的文档示例
  • 支持语法高亮
  • 可验证的代码片段
  • 提升文档质量

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();
};
}
java

新特性:

  • 支持守卫表达式
  • 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);
}
}
java

改进:

  • 性能优化
  • 更多平台支持
  • 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"
);
}
}
java

特点:

  • 可自定义解析逻辑
  • 支持本地缓存
  • 灵活的配置选项
  • 改进的可测试性

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() {
// 执行清理操作
}
}
}
}
java

建议:

  • 使用 try-with-resources
  • 采用 Cleaner 机制
  • 显式资源管理
  • 避免依赖终结器

总结

JDK 18 虽然是一个非 LTS 版本,但它带来了一些实用的改进。UTF-8 默认字符集的变更和简单 Web 服务器的引入都是非常实用的特性,可以提高开发效率。同时,代码片段的支持改进了文档质量,而模式匹配 Switch 和向量 API 的持续改进也显示了 Java 在语言特性和性能优化方面的努力。

对于开发者来说,建议:

  1. 使用 UTF-8 作为默认字符集
  2. 利用简单 Web 服务器进行快速原型开发
  3. 在文档中使用新的代码片段特性
  4. 关注模式匹配和向量 API 的发展
  5. 开始规划终结器的替代方案

虽然这是一个过渡版本,但其中的一些特性为未来的 Java 发展奠定了基础,值得开发者关注和学习。