Java23新特性教程 - 2024最新Java特性完整指南
Java23新特性教程 - 2024最新Java特性完整指南
目录
- Java23简介
- 环境搭建
- 模式中的原始类型、instanceof和switch(预览)
- Markdown文档注释
- 流收集器(第二次预览)
- 结构化并发(第三次预览)
- 作用域值(第三次预览)
- 类文件API(第二次预览)
- 灵活的构造器主体(第二次预览)
- 隐式声明的类和实例主方法(第三次预览)
- 模块导入声明(预览)
- ZGC默认分代模式
- 实际应用案例
- 总结与最佳实践
1. Java23简介
Java 23于2024年9月17日正式发布,是Oracle发布的又一个重要版本。Java 23在Java 22的基础上进一步增强了语言特性,提升了开发效率和代码质量。
主要特性列表:
✅ 模式中的原始类型、instanceof和switch(JEP 469):增强模式匹配能力
✅ Markdown文档注释(JEP 467):支持Markdown语法的Javadoc
✅ 流收集器(JEP 473):增强Stream API的收集能力
✅ 结构化并发(JEP 476):简化并发编程模型
✅ 作用域值(JEP 477):现代化的线程本地存储
✅ 类文件API(JEP 478):解析和生成类文件的API
✅ 灵活的构造器主体(JEP 480):增强构造器灵活性
✅ 隐式声明的类和实例主方法(JEP 481):简化小型程序开发
✅ 模块导入声明(JEP 484):简化模块依赖管理
✅ ZGC默认分代模式(JEP 482):提升垃圾收集性能
最新特性:了解Java语言的最新发展方向
提升效率:新特性可以大幅提升开发效率
代码质量:更好的代码可读性和维护性
性能优化:ZGC等性能改进
现代化编程:支持更现代的编程范式
非LTS版本:Java 23不是LTS版本,Java 21是当前LTS版本
预览特性:部分特性仍处于预览阶段
稳定性:生产环境建议使用LTS版本
2. 环境搭建
Windows系统
- 访问Oracle官网:https://www.oracle.com/java/technologies/downloads/#java23
- 选择Windows版本下载
- 运行安装程序,按照提示完成安装
- 记住安装路径(默认:
C:\Program Files\Java\jdk-23)
macOS系统
方式1:使用Homebrew(推荐)
brew install openjdk@23方式2:手动下载
- 访问Oracle或Adoptium官网下载macOS版本
- 安装后配置环境变量
Linux系统
# Ubuntu/Debian
sudo apt update
sudo apt install openjdk-23-jdk
# CentOS/RHEL
sudo yum install java-23-openjdk-develWindows
- 右键"此电脑" → "属性" → "高级系统设置" → "环境变量"
- 新建系统变量:
- 变量名:
JAVA_HOME - 变量值:
C:\Program Files\Java\jdk-23
- 变量名:
- 编辑Path变量,添加:
%JAVA_HOME%\bin
macOS/Linux
编辑 ~/.zshrc 或 ~/.bash_profile:
export JAVA_HOME=$(/usr/libexec/java_home -v 23)
export PATH=$JAVA_HOME/bin:$PATH然后执行:
source ~/.zshrcjava -version
# 应该显示:openjdk version "23" 或 java version "23"
javac -version
# 应该显示:javac 23IntelliJ IDEA
- File → Project Structure → Project
- 设置Project SDK为JDK 23
- 设置Language level为23
Eclipse
- Window → Preferences → Java → Installed JREs
- 添加JDK 23
- 在项目属性中设置Java Build Path使用JDK 23
3. 模式中的原始类型、instanceof和switch(预览)
Java 23增强了模式匹配功能,允许在模式匹配、instanceof和switch表达式中直接使用原始类型,使代码更加简洁。
基本用法
// Java 23之前:需要手动转换
Object obj = 42;
if (obj instanceof Integer) {
Integer i = (Integer) obj;
System.out.println(i);
}
// Java 23方式:直接模式匹配
Object obj = 42;
if (obj instanceof Integer i) {
System.out.println("Integer value: " + i);
}原始类型模式匹配
// 支持原始类型
Object value = 100;
// int类型模式匹配
if (value instanceof int i) {
System.out.println("int value: " + i);
}
// double类型模式匹配
Object doubleValue = 3.14;
if (doubleValue instanceof double d) {
System.out.println("double value: " + d);
}
// boolean类型模式匹配
Object boolValue = true;
if (boolValue instanceof boolean b) {
System.out.println("boolean value: " + b);
}基本用法
Object obj = 42;
// 使用switch表达式进行模式匹配
String result = switch (obj) {
case Integer i -> "Integer: " + i;
case Double d -> "Double: " + d;
case String s -> "String: " + s;
case null -> "null";
default -> "Unknown type";
};
System.out.println(result); // Integer: 42原始类型匹配
Object value = 100;
String type = switch (value) {
case int i -> "int: " + i;
case long l -> "long: " + l;
case double d -> "double: " + d;
case float f -> "float: " + f;
case boolean b -> "boolean: " + b;
case byte b -> "byte: " + b;
case short s -> "short: " + s;
case char c -> "char: " + c;
default -> "Other type";
};记录模式匹配
record Point(int x, int y) {}
Object obj = new Point(10, 20);
String description = switch (obj) {
case Point(int x, int y) when x > 0 && y > 0 ->
"Point in first quadrant: (" + x + ", " + y + ")";
case Point(int x, int y) ->
"Point: (" + x + ", " + y + ")";
default -> "Not a point";
};record Rectangle(Point topLeft, Point bottomRight) {}
Object obj = new Rectangle(new Point(0, 0), new Point(100, 100));
String info = switch (obj) {
case Rectangle(Point(int x1, int y1), Point(int x2, int y2)) ->
"Rectangle from (" + x1 + ", " + y1 + ") to (" + x2 + ", " + y2 + ")";
default -> "Not a rectangle";
};编译和运行需要启用预览特性:
# 编译
javac --enable-preview --release 23 PatternMatchingExample.java
# 运行
java --enable-preview PatternMatchingExamplepublic class TypeChecker {
public static String checkType(Object value) {
return switch (value) {
case int i -> "Primitive int: " + i;
case Integer i -> "Boxed Integer: " + i;
case long l -> "Primitive long: " + l;
case double d -> "Primitive double: " + d;
case String s -> "String: " + s;
case null -> "null value";
default -> "Unknown type: " + value.getClass().getName();
};
}
public static void main(String[] args) {
System.out.println(checkType(42)); // Primitive int: 42
System.out.println(checkType(100L)); // Primitive long: 100
System.out.println(checkType(3.14)); // Primitive double: 3.14
System.out.println(checkType("Hello")); // String: Hello
}
}4. Markdown文档注释
Java 23(JEP 467)支持在Javadoc注释中使用Markdown语法,使文档编写更加直观和高效,无需使用HTML标签。
标题
/**
* # 一级标题
* ## 二级标题
* ### 三级标题
*/
public class MarkdownExample {
}列表
/**
* 无序列表:
* - 项目1
* - 项目2
* - 项目3
*
* 有序列表:
* 1. 第一项
* 2. 第二项
* 3. 第三项
*/
public void example() {
}代码块
/**
* 行内代码:使用 `code` 语法
*
* 代码块:
* ```java
* public void method() {
* System.out.println("Hello");
* }
* ```
*/
public void codeExample() {
}强调
/**
* **粗体文本**
* *斜体文本*
* ~~删除线~~
*/
public void emphasis() {
}链接和图片
/**
* 链接:[链接文本](https://example.com)
* 图片:
*/
public void links() {
}表格
/**
* | 列1 | 列2 | 列3 |
* |-----|-----|-----|
* | 数据1 | 数据2 | 数据3 |
* | 数据4 | 数据5 | 数据6 |
*/
public void table() {
}/**
* # UserService
*
* 用户服务类,提供用户相关的业务逻辑。
*
* ## 功能特性
*
* - 用户注册
* - 用户登录
* - 用户信息查询
* - 用户信息更新
*
* ## 使用示例
*
* ```java
* UserService service = new UserService();
* User user = service.getUserById(1);
* ```
*
* ## 注意事项
*
* > 警告:此服务不是线程安全的,多线程环境下请使用同步机制。
*
* @author Java Developer
* @version 1.0
* @since 1.0
*/
public class UserService {
/**
* 根据用户ID获取用户信息
*
* @param userId 用户ID,必须大于0
* @return 用户对象,如果用户不存在返回null
* @throws IllegalArgumentException 当userId <= 0时抛出
*
* ## 示例
*
* ```java
* User user = getUserById(1);
* if (user != null) {
* System.out.println(user.getName());
* }
* ```
*/
public User getUserById(int userId) {
if (userId <= 0) {
throw new IllegalArgumentException("User ID must be positive");
}
// 实现逻辑
return null;
}
}# 生成包含Markdown的Javadoc
javadoc -d docs UserService.java生成的文档会自动将Markdown转换为HTML格式。
- 可读性:源代码中的注释更易读
- 简洁性:比HTML标签更简洁
- 标准化:使用标准的Markdown语法
- 兼容性:仍然支持传统HTML标签
5. 流收集器(第二次预览)
流收集器(Stream Gatherers,JEP 473)是Java 23的预览特性,提供了更灵活的流操作,允许自定义流元素的收集和转换逻辑。
使用gather方法
import java.util.stream.*;
import java.util.stream.Gatherers;
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 使用gather进行窗口操作
List<List<Integer>> windows = numbers.stream()
.gather(Gatherers.windowFixed(3))
.toList();
// 结果: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]windowFixed - 固定窗口
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);
List<List<Integer>> windows = numbers.stream()
.gather(Gatherers.windowFixed(2))
.toList();
// 结果: [[1, 2], [3, 4], [5, 6]]实际应用:计算移动平均
List<Double> prices = List.of(10.0, 12.0, 11.0, 13.0, 14.0, 15.0);
List<Double> movingAverages = prices.stream()
.gather(Gatherers.windowFixed(3))
.map(window -> window.stream()
.mapToDouble(Double::doubleValue)
.average()
.orElse(0.0))
.toList();
// 结果: [11.0, 12.0, 12.67, 14.0]windowSliding - 滑动窗口
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
List<List<Integer>> windows = numbers.stream()
.gather(Gatherers.windowSliding(3))
.toList();
// 结果: [[1, 2, 3], [2, 3, 4], [3, 4, 5]]fold - 折叠操作
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
List<Integer> cumulativeSum = numbers.stream()
.gather(Gatherers.fold(() -> 0, Integer::sum))
.toList();
// 结果: [1, 3, 6, 10, 15] (累积和)scan - 扫描操作
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
List<Integer> scanned = numbers.stream()
.gather(Gatherers.scan(() -> 0, Integer::sum))
.toList();
// 结果: [0, 1, 3, 6, 10, 15] (包含初始值)import java.util.stream.Gatherer;
// 自定义Gatherer:去重但保留顺序
Gatherer<Integer, ?, Integer> distinctOrdered = new Gatherer<>() {
@Override
public Integrator<Integer, Integer, Integer> integrator() {
return new Integrator<>() {
private java.util.Set<Integer> seen = new java.util.LinkedHashSet<>();
@Override
public boolean integrate(Integer element,
Downstream<? super Integer> downstream) {
if (seen.add(element)) {
return downstream.push(element);
}
return true;
}
};
}
};
List<Integer> numbers = List.of(1, 2, 2, 3, 3, 3, 4);
List<Integer> distinct = numbers.stream()
.gather(distinctOrdered)
.toList();
// 结果: [1, 2, 3, 4]案例1:批次处理
List<String> items = List.of("a", "b", "c", "d", "e", "f", "g");
List<List<String>> batches = items.stream()
.gather(Gatherers.windowFixed(3))
.toList();
// 结果: [["a", "b", "c"], ["d", "e", "f"], ["g"]]
// 处理每个批次
batches.forEach(batch -> {
System.out.println("Processing batch: " + batch);
processBatch(batch);
});案例2:查找峰值
List<Double> values = List.of(1.0, 3.0, 2.0, 5.0, 4.0, 3.0, 6.0);
List<Double> peaks = values.stream()
.gather(Gatherers.windowSliding(3))
.filter(window -> {
double left = window.get(0);
double middle = window.get(1);
double right = window.get(2);
return middle > left && middle > right;
})
.map(window -> window.get(1))
.toList();
// 结果: [3.0, 5.0, 6.0]6. 结构化并发(第三次预览)
结构化并发(Structured Concurrency,JEP 476)是Java 23的预览特性,提供了一种更安全、更易理解的并发编程模型。
结构化并发的核心思想:
- 任务的生命周期与代码块绑定
- 自动管理任务取消和异常处理
- 避免线程泄漏和资源泄漏
基本用法
import java.util.concurrent.StructuredTaskScope;
import java.util.concurrent.Future;
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> task1 = scope.fork(() -> fetchUserData("user1"));
Future<String> task2 = scope.fork(() -> fetchUserData("user2"));
scope.join(); // 等待所有任务完成
String result1 = task1.resultNow();
String result2 = task2.resultNow();
System.out.println(result1);
System.out.println(result2);
} catch (Exception e) {
e.printStackTrace();
}ShutdownOnFailure策略
// 任何一个任务失败,立即取消其他任务
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> task1 = scope.fork(() -> {
Thread.sleep(1000);
return "Task 1";
});
Future<String> task2 = scope.fork(() -> {
throw new RuntimeException("Task failed");
});
scope.join();
scope.throwIfFailed(); // 如果有失败,抛出异常
} catch (Exception e) {
System.out.println("Task failed: " + e.getMessage());
}ShutdownOnSuccess策略
// 任何一个任务成功,立即取消其他任务
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) {
Future<String> task1 = scope.fork(() -> {
Thread.sleep(2000);
return "Task 1";
});
Future<String> task2 = scope.fork(() -> {
Thread.sleep(500);
return "Task 2"; // 这个先完成
});
scope.join();
String result = scope.result(); // 返回第一个成功的结果
System.out.println(result); // Task 2
}示例1:并行调用多个API
record ApiResponse(String data) {}
public ApiResponse callMultipleApis() {
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<ApiResponse>()) {
Future<ApiResponse> api1 = scope.fork(() -> callApi1());
Future<ApiResponse> api2 = scope.fork(() -> callApi2());
Future<ApiResponse> api3 = scope.fork(() -> callApi3());
scope.join();
return scope.result();
} catch (Exception e) {
throw new RuntimeException("All APIs failed", e);
}
}示例2:并行处理数据
List<String> data = List.of("data1", "data2", "data3", "data4");
public List<String> processData(List<String> data) {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
List<Future<String>> futures = data.stream()
.map(item -> scope.fork(() -> processItem(item)))
.toList();
scope.join();
scope.throwIfFailed();
return futures.stream()
.map(Future::resultNow)
.toList();
}
}7. 作用域值(第三次预览)
作用域值(Scoped Values,JEP 477)是Java 23的预览特性,提供了一种在同一线程内传递不可变数据的机制。
创建和作用域值
import jdk.incubator.concurrent.ScopedValue;
// 定义作用域值
private static final ScopedValue<String> USERNAME = ScopedValue.newInstance();
// 设置和使用
ScopedValue.runWhere(USERNAME, "Alice", () -> {
String username = USERNAME.get();
System.out.println("Current user: " + username); // Alice
});嵌套作用域
private static final ScopedValue<String> USERNAME = ScopedValue.newInstance();
private static final ScopedValue<String> ROLE = ScopedValue.newInstance();
ScopedValue.runWhere(USERNAME, "Alice", () -> {
System.out.println("Outer: " + USERNAME.get()); // Alice
ScopedValue.runWhere(ROLE, "Admin", () -> {
System.out.println("Inner: " + USERNAME.get()); // Alice (继承)
System.out.println("Role: " + ROLE.get()); // Admin
});
});private static final ScopedValue<String> REQUEST_ID = ScopedValue.newInstance();
public void handleRequest() {
ScopedValue.runWhere(REQUEST_ID, generateRequestId(), () -> {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> task1 = scope.fork(() -> {
String id = REQUEST_ID.get(); // 可以访问
return processTask1(id);
});
Future<String> task2 = scope.fork(() -> {
String id = REQUEST_ID.get(); // 可以访问
return processTask2(id);
});
scope.join();
}
});
}8. 类文件API(第二次预览)
类文件API(Class-File API,JEP 478)提供了用于解析、生成和转换Java类文件的API。
解析类文件
import java.lang.classfile.*;
import java.nio.file.Files;
import java.nio.file.Path;
Path classFile = Path.of("Example.class");
byte[] bytes = Files.readAllBytes(classFile);
ClassModel classModel = ClassFile.of().parse(bytes);
// 获取类名
String className = classModel.thisClass().asInternalName();
System.out.println("Class name: " + className);
// 遍历方法
classModel.methods().forEach(method -> {
System.out.println("Method: " + method.methodName().stringValue());
});生成类文件
import java.lang.classfile.*;
byte[] bytes = ClassFile.of().build(ClassDesc.of("Hello"), classBuilder -> {
classBuilder.withMethod("main", MethodTypeDesc.of(CD_void, CD_String.arrayType()),
ClassFile.ACC_PUBLIC | ClassFile.ACC_STATIC, methodBuilder -> {
methodBuilder.withCode(codeBuilder -> {
codeBuilder.getstatic(ClassDesc.of("java.lang.System"), "out",
ClassDesc.of("java.io.PrintStream"));
codeBuilder.ldc("Hello, World!");
codeBuilder.invokevirtual(ClassDesc.of("java.io.PrintStream"), "println",
MethodTypeDesc.of(CD_void, CD_String));
codeBuilder.return_();
});
});
});9. 灵活的构造器主体(第二次预览)
灵活的构造器主体(Flexible Constructor Bodies,JEP 480)允许在调用super()或this()之前执行语句。
public class Parent {
public Parent(int value) {
System.out.println("Parent constructor: " + value);
}
}
public class Child extends Parent {
public Child(int value) {
// 现在可以在super()之前执行语句
int computedValue = computeValue(value);
super(computedValue);
System.out.println("Child constructor");
}
private int computeValue(int value) {
return value * 2;
}
}10. 隐式声明的类和实例主方法(第三次预览)
隐式声明的类和实例主方法(JEP 481)允许在未命名的类中定义main方法。
// Hello.java - 不需要public class声明
void main() {
System.out.println("Hello, World!");
}编译和运行:
javac --enable-preview --release 23 Hello.java
java --enable-preview Hello11. 模块导入声明(预览)
模块导入声明(JEP 484)简化了模块之间的依赖管理。
import module com.example.module;
public class ModuleImportExample {
public static void main(String[] args) {
// 使用模块中的类和方法
}
}12. ZGC默认分代模式
ZGC(Z Garbage Collector)在Java 23中默认启用了分代模式,提升了内存管理的效率。
# 启用ZGC(默认启用分代模式)
java -XX:+UseZGC -Xmx10g -Xms10g MyApplication
# 禁用分代模式(如果需要)
java -XX:+UseZGC -XX:-ZGenerational MyApplication- 减少GC暂停时间
- 提高吞吐量
- 更好的内存利用率
13. 实际应用案例
import java.util.concurrent.StructuredTaskScope;
import jdk.incubator.concurrent.ScopedValue;
private static final ScopedValue<String> REQUEST_ID = ScopedValue.newInstance();
public Response handleRequest(Request request) {
return ScopedValue.runWhere(REQUEST_ID, generateId(), () -> {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<User> userFuture = scope.fork(() -> fetchUser(request.userId()));
Future<Config> configFuture = scope.fork(() -> fetchConfig());
scope.join();
scope.throwIfFailed();
User user = userFuture.resultNow();
Config config = configFuture.resultNow();
return processRequest(user, config);
}
});
}List<Record> records = fetchRecords();
// 使用流收集器进行窗口分析
List<Double> movingAverages = records.stream()
.map(Record::value)
.gather(Gatherers.windowFixed(5))
.map(window -> window.stream()
.mapToDouble(Double::doubleValue)
.average()
.orElse(0.0))
.toList();public Object processValue(Object value) {
return switch (value) {
case int i -> processInt(i);
case double d -> processDouble(d);
case String s -> processString(s);
case Integer i -> processInteger(i);
case null -> handleNull();
default -> handleUnknown(value);
};
}14. 总结与最佳实践
- ✅ 模式匹配增强:更强大的类型检查和转换
- ✅ Markdown文档注释:更易读的文档编写
- ✅ 流收集器:更灵活的流处理
- ✅ 结构化并发:更安全的并发编程
- ✅ 作用域值:现代化的数据传递机制
- ✅ ZGC优化:更好的性能表现
预览特性:谨慎使用预览特性,API可能变化
性能考虑:ZGC分代模式可以提升性能
代码清晰:使用新特性提高代码可读性
渐进采用:逐步采用新特性
实践为主:多写代码练习
理解原理:理解每个特性的设计思想
关注更新:关注Java新版本的发展
社区参与:参与Java社区讨论
- ⚠️ 部分特性是预览版,可能在未来版本中调整
- ⚠️ 需要启用预览特性才能使用
- ⚠️ 生产环境谨慎使用预览特性
- ✅ LTS版本(Java 21)更适合生产环境
结语
Java 23带来了许多令人兴奋的新特性,进一步提升了Java语言的表达能力和开发效率。通过本教程的学习,相信你已经掌握了Java 23的核心特性。
记住:
- 多实践:理论结合实践,多写代码
- 理解设计:理解每个特性的设计思想
- 关注稳定:生产环境优先使用稳定特性
- 持续学习:关注Java语言的发展
祝你学习愉快,编程顺利! 🚀
本教程由Java突击队学习社区编写,如有问题欢迎反馈。