Snack4 是一款专为高性能场景设计的 Java JSON 库。其核心组件 JsonReader 采用非递归状态机架构,原生支持 流式解析 (Streaming) 与 结构自修复 (Auto-Repair),是处理 LLM(大模型)不稳定输出、超大 NDJSON 文件的理想选择。
1. 流式解析:从全量到增量的跨越
传统解析器要求 JSON 必须完整且一次性读入内存,而 Snack4 支持在数据流动的过程中,按块(Node)提取有效数据。
1.1 核心场景
- LLM 实时渲染:边生成边解析,无需等待对话结束即可更新 UI。
- NDJSON/JSONL:处理日志流或数据库导出的多行 JSON 对象。
- 低内存处理:在处理 GB 级文件时,内存占用保持在 KB 级别的缓冲区大小。
1.2 关键 API
JsonReader reader = new JsonReader(jsonStream);
// 方式 A:迭代器模式(推荐,语法最优雅)
for (ONode node : reader.iterableNext()) {
process(node);
}
// 方式 B:精准获取最后一个完整节点(常用于获取 LLM 最终状态)
ONode finalState = reader.readLast();
// 方式 C:手动控制分块读取
ONode next;
while ((next = reader.readNext()) != null) {
// 业务逻辑
}
2. 自动修复:容错能力的降维打击
当开启 Feature.Read_AutoRepair 后,JsonReader 会从一个“严格的校验者”转变为“聪明的补全者”。它通过维护内部的类型栈(Stack),在遇到非预期结束时,自动推导缺失的符号。
2.1 修复逻辑对照表
| 损坏类型 | 原始输入 (Broken) | 修复后输出 (Repaired) | 修复逻辑说明 |
|---|---|---|---|
| 关键字截断 | {"status": tru | {"status": true} | 未写完的 true 字面量自动修复为 true |
| 容器未闭合 | {"a":{"b":1 | {"a":{"b":1}} | 根据解析栈自动补全缺失的 } |
| 数组末尾逗号 | [1, 2, | [1, 2] | 自动忽略 Trailing Comma |
| 键值对缺失 | {"key": | {"key": null} | 发现冒号后直接结束,自动补齐值 |
| 非法字符干扰 | {"a":1} #comment | {"a":1} | 配合 Read_AllowComment 过滤非 JSON 内容 |
2.3 代码演示
// 即使是深度嵌套且严重截断的字符串
String brokenJson = "{\"user\":{\"tags\":[\"java\",\"ai\"";
Options opts = Options.of(Feature.Read_AutoRepair);
ONode node = JsonReader.read(brokenJson, opts);
System.out.println(node.toJson());
// 输出: {"user":{"tags":["java","ai"]}}
3. 进阶:处理 LLM 混合输出的最佳实践
LLM 有时会输出一段文字后紧跟一个 JSON,或者输出多个并列的 JSON 块。通过 Snack4 的组合特性,可以轻松应对这种复杂情况。
3.1 混合流解析模板
public void handleLlmStream(String rawOutput) {
// 开启自动修复 + 允许单引号(增加鲁棒性)
Options opts = Options.of(Feature.Read_AutoRepair, Feature.Read_AllowSingleQuotes);
JsonReader reader = new JsonReader(rawOutput, opts);
// 自动过滤流中的非有效 JSON 部分(如前导文字)
for (ONode node : reader.iterableNext()) {
if (node.isObject() || node.isArray()) {
// 只处理结构化数据
dispatchToBusiness(node);
}
}
}
3.2 性能提示
JsonReader 内部使用了 char[] 缓冲区(默认 8KB)和 StringBuilder 池化技术。
- 在处理字符转义(如
\u0020,\n)时,它会进行批量块复制,比逐字符解析快 3-5 倍。 - 支持 JavaScript Date 对象的特殊解析:
new Date(1710724859000)。
4. 总结
| 维度 | 流式读取与结构修复 | 普通模式 |
|---|---|---|
| 解析方式 | 流式指针滑动,不断解析 json 块 | 只解析一个 json 块,多出则异常 |
| 异常处理 | 自动修复,不抛异常 | 遇到一个冒号缺失即抛出 ParseException |
| LLM 适配 | 原生支持截断、关键字修复 | 需要开发者自行编写正则或预处理逻辑(不合规,则会抛出 ParseException) |
通过将 流式读取 与 自动修复 结合,Snack4 为开发者提供了一道坚固的数据防线,确保无论上游数据多么糟糕,下游业务逻辑都能获得稳定的结构化对象。