Java字符串高频拼接应避免+操作符,改用预设容量的StringBuilder复用;日志等场景用占位符替代隐式拼接;超大文本须流式处理避免OOM。

Java里用String高频拼接,本质是“边造垃圾边等扫地”,不是内存不够,而是垃圾产得太快、GC追不上。
为什么+拼接会瞬间压垮年轻代
每次str += "x",JVM都得新建一个String对象——因为String不可变。旧对象没被引用就成垃圾,但新对象立刻占位。1秒内循环10万次?就生成10万个短命对象,全堆在Eden区。Minor GC虽快(几十毫秒),可应用线程创建对象的速度是纳秒级的,GC线程根本跑不赢。结果就是Eden反复打满→频繁触发GC→CPU大量耗在停顿上,系统响应卡顿甚至超时。
核心优化:用StringBuilder代替+,且必须预设容量
不用StringBuilder只是第一步,光换类型不设初始容量,照样掉坑里:
- 默认构造函数只给16字符空间,拼到第17个字符就触发扩容——复制原数组、新建更大数组、再拷贝,反复多次,开销翻倍
- 正确做法:估算最终长度(比如拼1000个平均20字符的字符串,预估20000),乘以1.2留余量:
new StringBuilder(24000) - 循环外创建、循环内复用,绝不在for里反复
new StringBuilder()
别踩这些隐式拼接的雷
有些写法看着没拼接,其实暗中狂造对象:
立即学习“Java免费学习笔记(深入)”;
- 日志语句:
log.info("id=" + user.getId() + ", time=" + now)——即使日志级别是WARN,拼接仍执行,参数也照算 - 改用占位符:
log.info("id={}, time={}", user.getId(), now),仅当日志真正输出时才计算和拼接 - JDK13+慎用
String.format(),它内部用StringBuilder但不暴露容量控制;优先选String.formatted(),但仍需注意长度预估
超大文本场景:跳出“全加载再拼接”思维
如果数据来自文件、数据库游标或HTTP流,总量远超堆内存(比如几百MB日志行),硬拼必OOM:
- 放弃
list.stream().collect(Collectors.joining())这类全量加载方式 - 改用流式处理:逐行读取 → 直接写入
FileWriter或OutputStream→ 写完即丢弃该行引用 - 配合
try-with-resources确保流及时关闭,避免句柄泄漏拖垮整个JVM


















