Java 字符串操作:String 与 StringBuilder
在 Java 中处理文本时,你会频繁使用字符串。但 Java 提供了两种主要方式:String 和 StringBuilder。它们看似都能存文字,实际性能和用途差别很大。选错类型可能导致程序变慢甚至卡顿。下面直接告诉你怎么选、怎么用。
理解 String 的“不可变”特性
创建一个 String 对象后,它的内容就再也改不了。这不是限制,而是设计原则。
String name = "张三";
name = name + "同学"; // 表面上看是“修改”,其实是新建
上面这行代码实际做了三件事:
- 创建原始字符串
"张三"。 - 创建新字符串
"同学"。 - 拼接两者,生成第三个全新字符串
"张三同学",然后让变量name指向它。
旧的 "张三" 并未被修改,只是不再被引用,等着被垃圾回收。每次“修改”都意味着新建对象、分配内存、复制字符——频繁操作会严重拖慢程序。
适用场景:字符串内容确定不变,或只做少量拼接(比如拼一两次日志)。
使用 StringBuilder 高效拼接
当你需要反复修改字符串内容(比如循环中拼接),必须用 StringBuilder。
创建一个 StringBuilder 实例:
StringBuilder sb = new StringBuilder();
它内部维护一个可变的字符数组。所有“修改”操作都在这个数组上原地进行,避免重复创建对象。
常用操作步骤
-
调用
append()方法追加内容:sb.append("今天"); sb.append("天气"); sb.append("很好"); -
调用
toString()获取最终结果:String result = sb.toString(); // 得到 "今天天气很好" -
清空内容以便复用(可选):
sb.setLength(0); // 清空,但保留底层数组容量
循环中拼接示例
假设你要把数字 1 到 100 拼成一个字符串:
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 100; i++) {
sb.append(i).append(", ");
}
String numbers = sb.toString();
如果用 String 做同样操作,会创建约 100 个中间字符串对象,而 StringBuilder 只用一个底层数组,效率高出几十倍。
性能对比关键点
虽然不需要图表也能说清,但为直观展示差异,列出核心区别:
| 特性 | String |
StringBuilder |
|---|---|---|
| 可变性 | 不可变 | 可变 |
| 线程安全 | 是(因不可变) | 否 |
| 拼接性能(多次) | 极差 | 优秀 |
| 内存开销 | 高(每次新建) | 低(原地修改) |
| 适用场景 | 少量拼接、常量 | 大量拼接、动态构建 |
注意:如果你在多线程环境需要可变且线程安全的字符串,应使用
StringBuffer(它是StringBuilder的线程安全版本),但绝大多数单线程场景下StringBuilder更快。
如何选择?记住这两条规则
-
如果字符串只拼接一次或两次(比如组合用户姓名和ID),直接用
String++操作符。Java 编译器会自动优化成StringBuilder,你不用操心。 -
如果在循环里、递归中,或不确定拼接次数,立即使用
StringBuilder。这是避免性能陷阱的最简单方法。
例如,以下写法是危险的:
String result = "";
for (String item : list) {
result += item; // 每次循环都新建 String!
}
正确做法:
StringBuilder sb = new StringBuilder();
for (String item : list) {
sb.append(item);
}
String result = sb.toString();
初始化容量提升效率(进阶技巧)
StringBuilder 默认初始容量是 16 个字符。如果拼接内容远超此数,它会自动扩容(通常是翻倍),但扩容涉及数组复制,仍有开销。
预估长度后指定初始容量,可避免中途扩容:
// 预计最终字符串约 1000 字符
StringBuilder sb = new StringBuilder(1000);
这一步不是必须,但在处理大文本(如生成 HTML、JSON)时能进一步提升性能。
最后提醒:别混淆 equals 和 ==
无论是 String 还是 StringBuilder,比较内容是否相等时,永远不要用 ==。
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false(地址不同)
System.out.println(a.equals(b)); // true(内容相同)
StringBuilder sb1 = new StringBuilder("hello");
StringBuilder sb2 = new StringBuilder("hello");
System.out.println(sb1.equals(sb2)); // false!StringBuilder 没重写 equals
要比较两个 StringBuilder 的内容,先转成 String 再比:
sb1.toString().equals(sb2.toString()); // 正确
创建字符串时,问自己一句:“我会频繁改它吗?”
会 → 用 StringBuilder。
不会 → 用 String。
就这么简单。

暂无评论,快来抢沙发吧!