个人感觉 Java 18 提供的功能都没什么用,简单了解一下就好。
正式特性
【了解】UTF-8 作为默认字符集
Java 18 将 UTF-8 设为默认字符集,解决了很多字符编码相关的问题,Java 程序在不同平台上的行为会更加一致。
// 这些操作现在默认使用 UTF-8 编码
FileReader reader = new FileReader("file.txt");
FileWriter writer = new FileWriter("file.txt");
PrintStream out = new PrintStream("output.txt");在这之前,Java 使用的是 系统默认字符集,会导致同一段代码在不同操作系统上可能产生完全不同的结果。
字符集统一的好处
public class CharsetExample {
public static void main(String[] args) throws IOException {
String chinese = "你好,世界!";
// Java 18 之前,这在不同系统上可能有不同结果
try (FileWriter writer = new FileWriter("test.txt")) {
writer.write(chinese);
}
try (FileReader reader = new FileReader("test.txt")) {
char[] buffer = new char[1024];
int length = reader.read(buffer);
String result = new String(buffer, 0, length);
System.out.println("读取结果: " + result);
}
// 现在在所有平台上都会正确处理中文
System.out.println("默认字符集: " + Charset.defaultCharset());
// 输出: UTF-8
}
}影响的 API
以下 API 现在默认使用 UTF-8:
// 文件操作
new FileReader("file.txt") // 现在默认 UTF-8
new FileWriter("file.txt") // 现在默认 UTF-8
new PrintWriter("file.txt") // 现在默认 UTF-8
// 流操作
new InputStreamReader(inputStream) // 现在默认 UTF-8
new OutputStreamWriter(outputStream) // 现在默认 UTF-8
// 格式化输出
new PrintStream("file.txt") // 现在默认 UTF-8
new Formatter("file.txt") // 现在默认 UTF-8【了解】简单 Web 服务器
Java 18 引入了一个简单的 Web 服务器,主要用于开发和测试。
# 启动简单的文件服务器,服务当前目录
jwebserver
# 指定端口和目录
jwebserver -p 8080 -d /path/to/your/files
# 绑定到特定地址
jwebserver -b 127.0.0.1 -p 9000Nginx 不香么,我要用这个东西?
实际使用场景
# 快速分享文件
cd ~/Documents
jwebserver -p 8000
# 访问 http://localhost:8000 查看文件
# 测试静态网站
cd my-website/dist
jwebserver -p 3000
# 开发时的临时服务器
jwebserver -b 0.0.0.0 -p 8080 -d ./public这个工具主要用于:
快速原型开发:不需要配置复杂的服务器
文件分享:在局域网内快速分享文件
静态网站测试:测试前端项目
教学演示:简单的 HTTP 服务器示例
【了解】JavaDoc 代码片段
Java 18 引入了 @snippet 标签,可以让 JavaDoc 生成的代码示例更美观,而且支持从外部文件引入代码片段。
/**
* 计算两个数的最大公约数
*
* {@snippet :
* int a = 48;
* int b = 18;
* int gcd = MathUtils.gcd(a, b);
* System.out.println("GCD: " + gcd); // @highlight substring="GCD"
* }
*
* @param a 第一个数
* @param b 第二个数
* @return 最大公约数
*/
public static int gcd(int a, int b) {
// 实现代码...
}
/**
* 从外部文件引入代码片段
*
* {@snippet file="examples/QuickSort.java" region="main-algorithm"}
*
* @param arr 要排序的数组
*/
public static void quickSort(int[] arr) {
// 实现代码...
}@snippet 的高级功能
/**
* 演示数组操作
*
* {@snippet :
* int[] numbers = {3, 1, 4, 1, 5}; // @highlight
* Arrays.sort(numbers); // @highlight
* System.out.println(Arrays.toString(numbers)); // @highlight substring="toString"
* // 输出: [1, 1, 3, 4, 5] // @replace regex="输出:" replacement="结果:"
* }
*/
public void demonstrateArraySort() {
// 方法实现
}
/**
* 使用外部代码文件
*
* {@snippet file="examples/DatabaseExample.java" region="connection-setup"}
*
* 上面的代码展示了如何建立数据库连接。
*/
public void setupDatabase() {
// 方法实现
}外部文件示例(examples/DatabaseExample.java):
public class DatabaseExample {
public void example() {
// @start region="connection-setup"
String url = "jdbc:mysql://localhost:3306/mydb";
String username = "user";
String password = "password";
try (Connection conn = DriverManager.getConnection(url, username, password)) {
// 使用连接进行数据库操作
} catch (SQLException e) {
e.printStackTrace();
}
// @end
}
}不过这年头还有开发者阅读 JavaDoc 么?

【了解】使用方法句柄重新实现核心反射
Java 18 在内部使用方法句柄重新实现了核心反射功能,这个改进对开发者是透明的,但可以提供:
更好的性能:方法句柄比传统反射更快
更少的内存占用:减少了元数据开销
更好的 JIT 优化:编译器可以更好地优化
// 反射 API 的使用方式没有变化
Class<?> clazz = String.class;
Method method = clazz.getMethod("length");
Object result = method.invoke("Hello");
// 但底层实现使用了方法句柄,性能更好【了解】互联网地址解析 SPI
Java 18 引入了互联网地址解析的服务提供者接口(SPI),允许自定义 DNS 解析:
// 自定义地址解析器
public class CustomInetAddressResolver extends InetAddressResolver {
@Override
public Stream<InetAddress> lookupByName(String host, LookupPolicy lookupPolicy) {
// 自定义 DNS 解析逻辑
if ("myapp.local".equals(host)) {
return Stream.of(InetAddress.getByName("127.0.0.1"));
}
// 委托给默认解析器
return InetAddressResolver.platformResolver().lookupByName(host, lookupPolicy);
}
@Override
public String lookupByAddress(byte[] addr) {
// 自定义反向 DNS 解析
return InetAddressResolver.platformResolver().lookupByAddress(addr);
}
}这个特性主要用于:
企业内部 DNS:解析内部域名
负载均衡:自定义负载均衡策略
缓存优化:实现 DNS 缓存策略
测试环境:模拟不同的网络环境
【了解】弃用完成以供删除
Java 18 将 Finalization 标记为弃用并计划删除:
// 这种做法已被弃用
public class OldStyleResource {
@Override
protected void finalize() throws Throwable {
// 不推荐:依赖 finalize 进行资源清理
super.finalize();
}
}
// 推荐的资源管理方式
public class ModernResource implements AutoCloseable {
@Override
public void close() {
// 推荐:显式资源管理
}
}
// 使用 try-with-resources
try (ModernResource resource = new ModernResource()) {
// 使用资源
} // 自动调用 close()预览特性
【了解】switch 的模式匹配(第二次预览)
Java 18 继续完善 switch 的模式匹配:
// 需要启用预览功能
// javac --enable-preview --release 18 PatternMatchingExample.java
// java --enable-preview PatternMatchingExample
public String processValue(Object obj) {
return switch (obj) {
case String s -> "字符串: " + s;
case Integer i -> "整数: " + i;
case Long l -> "长整数: " + l;
case Double d -> "浮点数: " + d;
case null -> "空值";
default -> "其他类型: " + obj.getClass().getSimpleName();
};
}
// 结合条件判断(守卫模式)
public String processString(Object obj) {
return switch (obj) {
case String s && s.length() > 10 -> "长字符串: " + s.substring(0, 10) + "...";
case String s && s.isEmpty() -> "空字符串";
case String s -> "字符串: " + s;
case null -> "空值";
default -> "非字符串";
};
}与 Records 和 Sealed 类结合
public sealed interface Shape permits Circle, Rectangle, Triangle {}
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 double calculateArea(Shape shape) {
return switch (shape) {
case Circle(var radius) -> Math.PI * radius * radius;
case Rectangle(var width, var height) -> width * height;
case Triangle(var base, var height) -> 0.5 * base * height;
// 不需要 default,sealed 类保证完整性
};
}
// 更复杂的模式匹配
public String describeShape(Shape shape) {
return switch (shape) {
case Circle(var r) && r > 10 -> "大圆,半径:" + r;
case Circle(var r) -> "小圆,半径:" + r;
case Rectangle(var w, var h) && w == h -> "正方形,边长:" + w;
case Rectangle(var w, var h) -> "矩形,宽:" + w + ",高:" + h;
case Triangle(var b, var h) -> "三角形,底:" + b + ",高:" + h;
};
}孵化器特性
【了解】向量 API(第三次孵化器)
Java 18 继续改进向量 API:
import jdk.incubator.vector.*;
public class VectorOperations {
private static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;
// 向量化的数组求和
public static float vectorSum(float[] array) {
float sum = 0.0f;
int upperBound = SPECIES.loopBound(array.length);
// 向量化部分
FloatVector accVector = FloatVector.zero(SPECIES);
for (int i = 0; i < upperBound; i += SPECIES.length()) {
FloatVector vector = FloatVector.fromArray(SPECIES, array, i);
accVector = accVector.add(vector);
}
sum += accVector.reduceLanes(VectorOperators.ADD);
// 处理剩余元素
for (int i = upperBound; i < array.length; i++) {
sum += array[i];
}
return sum;
}
// 向量化的数组乘法
public static void vectorMultiply(float[] a, float[] b, float[] result) {
int upperBound = SPECIES.loopBound(a.length);
for (int i = 0; i < upperBound; i += SPECIES.length()) {
FloatVector va = FloatVector.fromArray(SPECIES, a, i);
FloatVector vb = FloatVector.fromArray(SPECIES, b, i);
FloatVector vr = va.mul(vb);
vr.intoArray(result, i);
}
// 处理剩余元素
for (int i = upperBound; i < a.length; i++) {
result[i] = a[i] * b[i];
}
}
public static void main(String[] args) {
float[] numbers = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f};
System.out.println("向量化求和: " + vectorSum(numbers));
float[] a = {1, 2, 3, 4, 5, 6, 7, 8};
float[] b = {8, 7, 6, 5, 4, 3, 2, 1};
float[] result = new float[8];
vectorMultiply(a, b, result);
System.out.println("向量化乘法结果: " + Arrays.toString(result));
}
}【了解】外部函数和内存 API(第二次孵化器)
Java 18 继续完善外部函数和内存 API:
import jdk.incubator.foreign.*;
public class ForeignFunctionExample {
public static void main(String[] args) throws Throwable {
// 获取系统链接器
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
// 查找 C 标准库函数 strlen
MemoryAddress strlenAddr = stdlib.lookup("strlen").orElseThrow();
// 创建函数描述符
FunctionDescriptor strlenDesc = FunctionDescriptor.of(
CLinker.C_LONG, // 返回类型
CLinker.C_POINTER // 参数类型
);
// 创建方法句柄
MethodHandle strlen = linker.downcallHandle(strlenAddr, strlenDesc);
// 分配内存并调用函数
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
MemorySegment cString = CLinker.toCString("Hello, Foreign Function!", scope);
long length = (long) strlen.invoke(cString);
System.out.println("字符串长度: " + length);
}
// 调用 printf 函数
MemoryAddress printfAddr = stdlib.lookup("printf").orElseThrow();
FunctionDescriptor printfDesc = FunctionDescriptor.of(
CLinker.C_INT,
CLinker.C_POINTER
);
MethodHandle printf = linker.downcallHandle(printfAddr, printfDesc);
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
MemorySegment formatStr = CLinker.toCString("Hello from Java %d!\n", scope);
printf.invoke(formatStr, 2024);
}
}
}性能改进
【了解】JIT 编译器优化
Java 18 包含了多项 JIT 编译器优化:
更好的循环优化:改进了循环展开和向量化
方法内联优化:更智能的内联决策
逃逸分析改进:减少不必要的堆分配
【了解】垃圾收集器改进
G1 垃圾收集器优化
# G1 在 Java 18 中的性能改进
java -XX:+UseG1GC \
-XX:MaxGCPauseMillis=100 \
-XX:G1HeapRegionSize=16m \
MyAppZGC 和 Shenandoah 优化
# ZGC 改进
java -XX:+UseZGC \
-XX:ZCollectionInterval=0 \
MyApp
# Shenandoah 改进
java -XX:+UseShenandoahGC \
-XX:ShenandoahGCMode=iu \
MyApp总结
Java 18 虽然没有引入革命性的特性,但在基础设施方面做了很多改进。UTF-8 作为默认字符集解决了跨平台一致性问题,简单 Web 服务器为开发和测试提供了便利。
switch 模式匹配的继续完善为未来的正式版本做了准备,向量 API 和外部函数 API 的改进也为高性能计算提供了更好的支持。
虽然 Java 18 的特性看起来不够亮眼,但这些基础改进为后续版本奠定了重要基础,特别是在跨平台兼容性和开发工具方面的提升。