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 |
| 内存占用 |
恒定缓冲区 (Buffer-based) |
恒定缓冲区 (Buffer-based) |
| LLM 适配 |
原生支持截断、关键字修复 |
需要开发者自行编写正则或预处理逻辑(不合规,则会抛出 ParseException) |
通过将 流式读取 与 自动修复 结合,Snack4 为开发者提供了一道坚固的数据防线,确保无论上游数据多么糟糕,下游业务逻辑都能获得稳定的结构化对象。