优化字符串拼接需优先复用静态子串、预设StringBuilder容量并复用实例、善用String.join等高阶API,避免隐式重复与内存泄漏。

处理大量重复子串的拼接,核心不是“怎么连”,而是“怎么不连”——优先复用、避免复制、按需固化。关键在于识别重复模式、控制对象生命周期、合理利用 JVM 机制,而非盲目堆 append。
识别并提取高频重复子串,统一管理
若待拼接内容中存在固定前缀(如 "[INFO] ")、状态标识("SUCCESS"、"FAILED")或模板片段("id=
- 将这些子串声明为 static final String,确保编译期入常量池,运行时零分配
- 对真正高频且内容稳定的枚举值、协议字段等,可谨慎调用 .intern()(注意:仅限已知有限集合,禁用在动态 ID、时间戳上)
- 避免写成
sb.append("[INFO] ").append(msg)→ 改为sb.append(LOG_PREFIX).append(msg),LOG_PREFIX 是 static final
用 StringBuilder 预估总长 + 复用实例,禁用中途 toString
重复子串往往意味着结构固定、长度可预测(例如每条日志含相同前缀+可变内容+换行符)。此时容量预设收益极大。
- 估算单条记录长度(如前缀10字 + 内容均值80字 + 分隔符2字 + 换行2字 = 94),乘以总数(如10万条)→ 初始容量设为 10_0000 * 94 ≈ 9.4M,取整 10_000_000
- 创建一次:
StringBuilder sb = new StringBuilder(10_000_000),全程复用 - 绝对不在循环内调用
sb.toString()获取中间结果;只在最终输出前调用一次 - 若需分段生成多个字符串(如按批次写文件),用
sb.setLength(0)清空比新建更轻量
替代方案:StringJoiner 或 String.join 适配结构化重复
当重复体现在“同结构多实例”上(如生成 CSV 行、SQL IN 列表、HTTP Header 值),直接用高阶封装更安全简洁。
立即学习“Java免费学习笔记(深入)”;
-
String.join(", ", list):适合纯元素拼接,底层自动用 StringBuilder 且有容量优化,无需手动预估 -
new StringJoiner(",", "[", "]"):适合带前后缀的重复格式,如生成 JSON 数组["a","b","c"],自动处理分隔逻辑,避免手写 if-else 判首尾 - 二者均不适用于“子串嵌套重复”(如模板中某字段反复出现),此时仍需 StringBuilder 手动控制
警惕隐式重复与内存陷阱
有些“重复”是代码写法引入的,而非业务本身需要。
- 日志拼接别写
log.info("user=" + u.getName() + ", id=" + u.getId())—— 即使日志关闭,拼接仍执行,且每次生成新字符串。改用占位符:log.info("user={}, id={}", u.getName(), u.getId()) - 避免
substring()后再拼接大文本:JDK7+ 虽已修复共享数组问题,但若从 10MB 字符串中截取 10 字符再参与拼接,仍会短暂持有原大数组引用,建议new String(str.substring(...))强制隔离 - 不要对
sb.toString().intern()这类链式调用抱幻想——先造堆对象,再入池,白占一次内存


















