用 StringBuilder 生成 XML/JSON 时需预估容量、复用实例、就地编辑:显式初始化足够容量避免扩容拷贝,循环外声明并复用同一实例,利用 delete/insert/replace 等原地操作替代字符串截取拼接,链式调用确保零中间对象。

在生成复杂 XML 或 JSON 文本时,用 StringBuilder 代替字符串拼接(如 += 或多个 String.concat())能直接避开不可变性带来的对象爆炸,把内存开销压到最低。关键不是“用了 StringBuilder”,而是怎么用——预估、复用、就地编辑,三者缺一不可。
预设足够容量,避免扩容拷贝
XML/JSON 往往结构固定、长度可估。比如生成 1000 个用户节点,每个含 name、id、status 字段,平均占 120 字符,加上标签、逗号、缩进、括号等固定符号,总长约为 125000 字符。此时应:
- 显式初始化:
new StringBuilder(130000)(留 4% 余量) - 不依赖默认 16 容量,否则 1000 次追加会触发多次扩容(每次按
old × 2 + 2增长),引发数组复制和内存碎片 - 对不确定但有上限的场景(如单条日志 ≤ 8KB),设为
new StringBuilder(8192)即可基本免扩容
全程复用实例,不在循环里反复 new
常见误区是“每次拼一条记录就 new 一个 StringBuilder”。这等于放弃所有优势——每次新建都重置 char[]、浪费初始化开销、还增加 GC 压力。
- 正确做法:在方法开头声明一次,循环内只调用
append()、insert()等 - 示例(生成 JSON 数组):
StringBuilder sb = new StringBuilder(50000).append('[');<br> for (User u : users) {<br> sb.append('{')<br> .append("\"id\":").append(u.getId())<br> .append(",\"name\":\"").append(u.getName()).append('"')<br> .append('}').append(',');<br> }<br> if (users.size() > 0) sb.deleteCharAt(sb.length() - 1); // 删末尾逗号<br> sb.append(']');
用原地操作替代截取+拼接
复杂格式常需动态调整:补字段、删冗余逗号、替换占位符、插入缩进。若用 String 拆分再拼,每一步都新建对象;而 StringBuilder 可直接定位修改:
立即学习“Java免费学习笔记(深入)”;
- 删末尾字符:
deleteCharAt(sb.length() - 1)或delete(sb.length() - 1, sb.length()) - 替换模板段:
replace(start, end, "{\"status\":\"OK\"}") - 在开头加根标签:
insert(0, "<root>")</root>和append("") - 注意索引是左闭右开,
insert(i, s)表示插在第 i 个字符前(i 可等于当前 length)
链式调用让逻辑紧凑,不额外分配
所有修改方法(append、insert、delete、replace)都返回 this,天然支持链式写法。它不只是写起来顺,本质是全程复用同一 char[],不创建中间 String:
- 例如清洗并包装一段原始 JSON:
sb.delete(0, sb.indexOf("{") + 1) // 删前导乱码<br> .insert(0, "{\"data\":")<br> .append("}") - 对比 String 写法:
s = s.substring(...); s = "{" + s + "}"→ 至少 2 次新对象


















