应直接换用StringBuilder:循环外创建一次、循环内只append、最后调用一次toString()。因String不可变,+拼接每轮新建StringBuilder和String对象,导致高频Young GC甚至OOM;需复用实例、预估容量、延迟toString。

直接换用 StringBuilder,在循环外创建一次、循环内只 append、最后调用一次 toString() —— 这是最有效且必须做的改动。
为什么 + 拼接会内存暴涨
String 是不可变对象,每次 result += "x" 实际被编译成:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- new StringBuilder()(创建新对象)
- append(旧字符串) + append("x")
- toString()(生成新 String)
- 旧 result 立即失去引用,但还堆里占着位置
死循环中每轮至少新增 2 个堆对象。Eden 区几秒就满,触发高频 Young GC,大量短命对象来不及回收,部分还会晋升老年代,最终 OOM。
正确使用 StringBuilder 的三个关键点
-
复用实例:循环前 new 一次,不要写成
for (...) { new StringBuilder().append(...).toString(); } -
预估容量:如拼接 1000 个平均长度 10 的字符串,加逗号分隔,可设
new StringBuilder(1000 * 10 + 999),避免内部数组反复扩容 - 延迟 toString():只在循环结束后调用一次,不在循环里反复获取中间字符串
其他更安全或更简洁的替代方式
- 集合转字符串:用
String.join(",", list),底层自动用 StringBuilder,还处理 null - 带格式拼接:JDK 8+ 的
StringJoiner支持前缀/后缀/分隔符 - 流式处理:
list.stream().collect(Collectors.joining(",")),语义清晰、不易出错 - 极小规模(2~3 次):编译器会优化常量拼接,+ 也无妨;但逻辑不确定时仍建议统一用 StringBuilder
容易被忽略的隐式陷阱
- 日志拼接:
log.info("id=" + id + ", name=" + name)—— 即使日志关闭,拼接仍执行;应改用占位符log.info("id={}, name={}", id, name) - SQL 拼接:别手拼 SQL,改用 PreparedStatement 绑定参数
- 模板内容:用
String.formatted()(JDK 15+)或MessageFormat,避免临时对象堆积

















