StringBuilder 更快是因为 String 不可变,每次 + 拼接都创建新对象,而 StringBuilder 可变、内部用字符数组缓存,append() 仅追加数据(扩容时才新建数组),配合预估容量、避免循环中 toString() 和统一 print,能显著提升大批量文本输出性能。

直接用 + 拼接字符串输出大文本,会频繁创建新 String 对象,触发大量临时对象分配和 GC,明显拖慢控制台输出性能。用 StringBuilder 在内存中一次性组装好完整文本,再调用一次 System.out.print() 或 println(),能显著减少开销。
为什么 StringBuilder 更快?
String 是不可变的,每次 + 拼接都会生成新对象;而 StringBuilder 是可变的,内部用字符数组缓存内容,append() 只是往数组里追加数据(扩容时才新建数组)。对几百行日志、大段 HTML 或 JSON 格式化输出这类场景,性能差距可达数倍。
基本用法:替换 + 拼接,避免嵌套 toString()
不要在循环里反复调用 sb.toString() 再拼接——这又退化成 String 拼接。正确做法是全程只操作 StringBuilder,最后统一输出:
- 初始化时预估容量(如
new StringBuilder(4096)),减少数组扩容次数 - 用
append()累加所有片段:字符串、数字、布尔值、null(自动转为 "null")都支持 - 避免在循环内调用
toString(),除非真需要中间结果 - 输出前检查是否为空,避免打印空行(可选)
批量输出场景:先组装,再 print
比如生成表格、日志列表或模拟文件内容:
立即学习“Java免费学习笔记(深入)”;
StringBuilder sb = new StringBuilder(8192);
sb.append("=== 用户报告 ===\n");
for (User u : users) {
sb.append("ID: ").append(u.getId())
.append(", 名称: ").append(u.getName())
.append(", 状态: ").append(u.isActive() ? "启用" : "禁用")
.append("\n");
}
sb.append("总计 ").append(users.size()).append(" 条记录\n");
System.out.print(sb); // 一次输出,不是 println(避免末尾多一行)
注意:用 print() 而非 println(),因为换行已由 append("\n") 显式控制,更精确。
进阶技巧:复用与线程安全
StringBuilder 不是线程安全的,但单线程下可复用实例提升效率:
- 方法内声明局部变量最安全(JVM 会做逃逸分析,常优化为栈上分配)
- 若需跨方法复用,可用
setLength(0)清空内容,比新建对象轻量 - 多线程环境请改用
StringBuffer(同步开销大,一般不推荐)或确保每个线程独占实例 - 不需要时无需手动清空,局部变量自然被回收
不复杂但容易忽略:关键不在“用了 StringBuilder”,而在“只 toString 一次”和“控制好换行与容量”。对千行级文本,这种写法能让输出快得多,也更可控。


















