老生常谈的字符串拼接
作为Java开发者,String拼接是每天都要做的操作,String拼接:用+还是StringBuilder?
- 三种方式的性能对比
// 方法1:使用 + 拼接
String result1 = "Hello" + " " + "World" + "!";// 方法2:使用 StringBuilder
StringBuilder sb = new StringBuilder();
sb.append("Hello").append(" ").append("World").append("!");
String result2 = sb.toString();// 方法3:使用 String.concat()
String result3 = "Hello".concat(" ").concat("World").concat("!");
- 编译器背后的秘密
情况1:编译期优化
// 编译前:
String str = "a" + "b" + "c";// 编译后:
String str = "abc"; // 直接合并成常量!
情况2:循环中的陷阱
// 反例 - 在循环中使用 +
String result = "";
for (int i = 0; i < 100; i++) {result += i; // 每次循环都创建StringBuilder!
}// 正例 - 在循环中使用StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++) {sb.append(i); // 只创建一个StringBuilder
}
String result = sb.toString();
- 熟悉底层原理
问题1:String为什么不可变?
public final class String {private final char value[]; // final修饰,不可变// ...
}
· 线程安全
· 缓存哈希值
· 字符串常量池复用
问题2:StringBuilder和StringBuffer区别?
· StringBuilder:非线程安全,性能高
· StringBuffer:线程安全,性能较低
- 实际开发选择指南
// 场景1:少量固定字符串 → 直接用 +
String message = "姓名:" + name + ",年龄:" + age;// 场景2:循环或大量拼接 → StringBuilder
StringBuilder sql = new StringBuilder("SELECT * FROM users WHERE 1=1");
if (name != null) {sql.append(" AND name = '").append(name).append("'");
}
if (age > 0) {sql.append(" AND age = ").append(age);
}// 场景3:已知最终长度 → 设置初始容量
StringBuilder sb = new StringBuilder(1024); // 避免扩容开销
- 性能测试数据
// 测试结果参考(10000次拼接):
// + 拼接:约 150ms
// StringBuilder:约 5ms
// StringBuffer:约 8ms
知识要点:
-
- 操作符:适合少量拼接,编译器会优化
- StringBuilder:适合循环或未知次数的拼接
- StringBuffer:需要在多线程环境下使用
- 关键区别:+ 在循环中会创建多个StringBuilder对象
记住:在循环中拼接字符串,一定要用StringBuilder!
