硬核|Java 后端专家 Agent 项目中的 JDK 新特性实战
作者:白晨ovis 首发平台:掘金 项目源码:gitee.com/abao123/bac… 标签:Java / JDK 21 / Spring Boot / 新特性 / 实战
一、前言
本文带你深入剖析 Java 后端专家 Agent 项目中使用的 JDK 新特性,从 JDK 8 到 JDK 21,覆盖 函数式编程、不可变集合、Stream API、NIO 增强 等核心特性。
二、项目技术栈与 JDK 版本
<!-- pom.xml -->
<java.version>21</java.version>
<maven.compiler.source>21</maven.compiler.source>
项目基于 Spring Boot 3.4.5 + JDK 21,充分利用现代 Java 的新特性。
三、JDK 新特性全景图
| 特性 | JDK 版本 | 使用次数 | 代码示例 |
|---|---|---|---|
| Lambda 表达式 | 8 | 5 | (a, b) -> a + b |
| Stream API | 8 | 4 | stream().mapToDouble().average() |
| 方法引用 | 8 | 4+ | EvalResult::getOverallScore |
| Optional | 8 | 4 | .orElse(0.0) |
| Map.merge() | 8 | 3 | map.merge(key, val, Integer::sum) |
| Map.getOrDefault() | 8 | 2 | map.getOrDefault(key, default) |
| ConcurrentHashMap | 8 | 1 | new ConcurrentHashMap<>() |
| List.of() / Map.of() | 9 | 27 | List.of("a", "b") |
| String.isBlank() | 11 | 12 | str.isBlank() |
| Path.of() | 11 | 1 | Path.of(dir, file) |
| Files 新方法 | 11 | 6 | Files.writeString() |
| switch 表达式 | 14 | 1 | switch(x) { case A -> ... } |
| removeFirst() | 21 | 1 | list.removeFirst() |
四、核心特性详解
4.1 Lambda 表达式 + 方法引用(JDK 8)
使用场景:Stream 操作、比较器、函数式接口
// ModelRouterService.java - 模型缓存懒加载
return modelCache.computeIfAbsent(modelName, name -> {
log.info("创建 ChatModel 实例: {}", name);
// 创建 ChatModel...
});
// MarkdownDocumentLoader.java - 排序比较器
documents.sort((a, b) ->
a.getMetadata().getSource().compareTo(b.getMetadata().getSource())
);
// ConversationLogService.java - Map 合并统计
toolUsage.merge(tc.getTool(), 1, Integer::sum);
方法引用三剑客:
// 对象方法引用
EvalResult::getOverallScore // 等价于 r -> r.getOverallScore()
// 静态方法引用
Integer::sum // 等价于 (a, b) -> Integer.sum(a, b)
// 构造方法引用
ArrayList::new // 等价于 () -> new ArrayList()
4.2 Stream API(JDK 8)
使用场景:数据统计、集合转换、聚合计算
// AgentEvaluatorService.java - 评估结果统计分析
double avgScore = results.stream()
.mapToDouble(EvalResult::getOverallScore)
.average()
.orElse(0.0);
// 各维度平均分计算
dimensionScores.put("relevance", Math.round(
results.stream()
.mapToDouble(EvalResult::getRelevanceScore)
.average()
.orElse(0) * 100.0
) / 100.0);
// 按分类聚合统计
categoryScores.merge(cat, r.getOverallScore(), Double::sum);
categoryCounts.merge(cat, 1, Integer::sum);
Stream 流水线三件套:
list.stream()
.filter(Objects::nonNull) // 中间操作:过滤
.map(Object::getName) // 中间操作:转换
.collect(Collectors.toList()); // 终止操作:收集
4.3 不可变集合工厂(JDK 9+)
List.of() / Map.of() — 代码更简洁,线程安全
// QuestionClassifier.java - 问题分类关键词
private static final List<String> COMPLEX_KEYWORDS = List.of(
"设计", "架构", "生成", "方案", "实现",
"优化", "重构", "审查", "分析", "诊断"
);
private static final List<String> SIMPLE_KEYWORDS = List.of(
"是什么", "哪个", "多少", "如何实现",
"介绍一下", "讲讲", "说说"
);
// AgentEvaluatorService.java - 测试用例定义
List.of("支付", "高可用", "幂等", "对账", "风控", "高并发"),
List.of("退款", "原路退回", "异步", "幂等", "状态"),
// AgentService.java - 返回状态信息
return Map.of(
"tool_count", toolRegistry.getToolCount(),
"tools", toolRegistry.getToolNames()
);
// ModelRouterService.java - 路由器状态
return Map.of(
"primary_model", mp.getPrimary(),
"fallback_model", mp.getFallback(),
"smart_routing", mp.isSmartRouting(),
"cached_models", modelCache.keySet()
);
优势对比:
| 方式 | JDK 8 写法 | JDK 9+ 写法 |
|---|---|---|
| List | Arrays.asList("a", "b") | List.of("a", "b") |
| Map | new HashMap<>() + put | Map.of("key", "value") |
| 线程安全 | 需 Collections.unmodifiableList() | 原生不可变 |
| 空值 | 允许 | 不允许(抛异常) |
4.4 String 增强(JDK 11+)
isBlank() — 比 isEmpty() + trim() 更优雅
// QuestionClassifier.java
if (userInput == null || userInput.isBlank()) {
return QuestionType.NORMAL;
}
// SqlGeneratorTool.java - 参数校验
if (requirement == null || requirement.isBlank()) {
return "[ERROR] 缺少 requirement 参数";
}
// CodeReviewTool.java - 多重校验
if (code == null || code.isBlank()) {
return "[ERROR] 缺少代码内容";
}
if (focus != null && !focus.isBlank()) {
// 只在 focus 不为空且非空白时处理
}
JDK 11 String API 全家桶:
" hello ".isBlank(); // true(包含空白字符)
"hello".isEmpty(); // false(空字符串才为 true)
"hello".repeat(3); // "hellohellohello"
"Hello".toLowerCase(); // "hello"
"hello".lines(); // 按换行分割成 Stream
4.5 NIO 增强(JDK 11+)
Files 新方法 — 文件操作更简洁
// ConversationLogService.java - NIO 文件操作
// 1. 创建目录(自动创建父目录)
Files.createDirectories(logFilePath.getParent());
// 2. 写入字符串(原子操作)
Files.writeString(logFilePath, json + "\n",
StandardOpenOption.CREATE,
StandardOpenOption.APPEND);
// 3. 读取所有行
List<String> lines = Files.readAllLines(logFilePath);
// 4. Path.of() — 路径构建
this.logFilePath = Path.of(dir, file);
对比传统写法:
// ❌ JDK 8 写法
Path path = Paths.get(dir, file);
Files.createDirectories(path.getParent());
BufferedWriter writer = Files.newBufferedWriter(path,
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
writer.write(json + "\n");
writer.close();
// ✅ JDK 11+ 写法
Path path = Path.of(dir, file);
Files.createDirectories(path.getParent());
Files.writeString(path, json + "\n",
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
4.6 switch 表达式(JDK 14+)
箭头表达式 — 更简洁,避免 fall-through
// ModelRouterService.java - 模型路由
public ChatModel getChatModel(QuestionType questionType) {
if (!modelProps.isSmartRouting()) {
return getOrCreateModel(modelProps.getPrimary());
}
// ✅ switch 表达式(箭头语法)
String modelName = switch (questionType) {
case SIMPLE -> modelProps.getFast(); // 简单问题 → 快模型
case COMPLEX -> modelProps.getStrong(); // 复杂问题 → 强模型
default -> modelProps.getPrimary(); // 默认 → 主模型
};
return getOrCreateModel(modelName);
}
对比传统写法:
// ❌ 传统 switch(易出错)
String modelName;
switch (questionType) {
case SIMPLE:
modelName = modelProps.getFast();
break;
case COMPLEX:
modelName = modelProps.getStrong();
break;
default:
modelName = modelProps.getPrimary();
}
// ✅ switch 表达式(简洁安全)
String modelName = switch (questionType) {
case SIMPLE -> modelProps.getFast();
case COMPLEX -> modelProps.getStrong();
default -> modelProps.getPrimary();
};
4.7 JDK 21 新特性:SequencedCollection
removeFirst() / removeLast() — 双端队列的现代化 API
// AgentService.java - 对话历史管理
while (chatHistory.size() > maxHistory) {
chatHistory.removeFirst(); // ✅ JDK 21 新方法
}
背景: JDK 21 引入了 SequencedCollection 接口,ArrayList 实现了该接口,提供了 removeFirst() 和 removeLast() 方法。
// 之前的写法
chatHistory.remove(0); // ❌ 可读性差
// JDK 21 新写法
chatHistory.removeFirst(); // ✅ 语义清晰
chatHistory.removeLast(); // ✅ 语义清晰
五、工程化应用场景
5.1 配置常量定义
// ✅ 推荐:不可变集合
private static final List<String> SUPPORTED_LANGS = List.of(
"Java", "Python", "Go", "Rust", "JavaScript"
);
private static final Map<String, Integer> PRIORITY_MAP = Map.of(
"critical", 100,
"high", 75,
"medium", 50,
"low", 25
);
5.2 多维度统计
// 一次遍历,多种统计
Map<String, Integer> categoryCount = new HashMap<>();
Map<String, Double> categoryScore = new HashMap<>();
results.forEach(r -> {
String cat = r.getCategory();
categoryCount.merge(cat, 1, Integer::sum);
categoryScore.merge(cat, r.getScore(), Double::sum);
});
// 计算平均值
categoryScore.forEach((cat, sum) ->
categoryScore.put(cat, sum / categoryCount.get(cat))
);
5.3 空值安全处理
// ❌ 传统写法
String name = user.getName();
if (name == null) {
name = "匿名";
}
// ✅ Optional + orElse
String name = Optional.ofNullable(user.getName())
.orElse("匿名");
// ✅ Stream + orElse
double avg = results.stream()
.mapToDouble(EvalResult::getScore)
.average()
.orElse(0.0);
六、面试加分点
Q:为什么要用 List.of() 而不是 Arrays.asList()?
✅ 面试回答:
- 语义更清晰:
List.of()明确表示创建不可变集合- 性能优化:JVM 可以做更多优化(如常量折叠)
- 线程安全:原生不可变,无需额外包装
- 禁止 null:提前暴露问题,而不是运行时才发现
- 不可修改:调用 add/remove 会抛 UnsupportedOperationException
Q:removeFirst() 和 remove(0) 有什么区别?
✅ 面试回答:
- 语义差异:
removeFirst()语义更明确,一看就知道是移除第一个- 性能差异:
ArrayList.remove(0)需要移动所有元素;LinkedList.removeFirst()是 O(1)- 接口抽象:
SequencedCollection接口让双端操作统一化- 向后兼容:
removeFirst()是 JDK 21 新增,remove(0)兼容旧版本
七、项目地址
Java 后端专家 Agent 完整源码:
核心模块 JDK 特性应用
| 模块 | 主要特性 |
|---|---|
AgentService | removeFirst()、Map.of()、Stream API |
ModelRouterService | switch 表达式、ConcurrentHashMap、Lambda |
AgentEvaluatorService | Stream API、方法引用、List.of() |
ConversationLogService | Path.of()、Files.writeString()、Map.merge() |
QuestionClassifier | List.of()、String.isBlank() |
八、总结
| JDK 版本 | 特性数量 | 核心价值 |
|---|---|---|
| JDK 8 | 5 | Lambda、Stream、Optional、函数式编程基础 |
| JDK 9+ | 3 | 不可变集合工厂、String 增强、NIO 增强 |
| JDK 11 | 2 | Path.of()、Files 新方法 |
| JDK 14 | 1 | switch 表达式 |
| JDK 21 | 1 | SequencedCollection(removeFirst) |
掌握这些 JDK 新特性,不仅能写出更简洁、更安全的代码,还能在面试中展示你对现代 Java 的深入理解!
如果对你有帮助,欢迎点赞 + 收藏!