在 Java 中,字符串(String)是不可变(immutable)的,这意味着一旦创建,其内容就不能被修改。"追加"操作实际上是创建一个新的字符串,将原字符串和要追加的内容连接起来。

以下是 Java 中几种常用的字符串追加(拼接)方法,从传统到现代,各有优缺点。
使用 或 运算符
这是最直观、最简单的方法,适用于少量字符串的拼接。
示例代码:
public class StringConcatenation {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = " ";
String s3 = "World";
// 使用 + 运算符
String result1 = s1 + s2 + s3;
System.out.println(result1); // 输出: Hello World
// 使用 += 运算符
String temp = s1;
temp += s2;
temp += s3;
System.out.println(temp); // 输出: Hello World
}
}
工作原理与缺点:
- 底层实现:在 Java 中,使用 或 进行字符串拼接时,编译器会自动将其转换为
StringBuilder或StringBuffer的append()方法。s1 + s2会被编译成new StringBuilder().append(s1).append(s2).toString()。 - 性能问题:如果在循环中频繁使用 ,会创建大量的
StringBuilder对象,导致性能下降和内存浪费。
不推荐的用法(在循环中):
// 错误示范:性能很差
String badResult = "";
for (int i = 0; i < 1000; i++) {
badResult += "a"; // 每次循环都创建一个新的 StringBuilder 和一个新的 String
}
使用 StringBuilder
StringBuilder 是 Java 5 引入的类,它是一个可变的字符序列,当需要进行大量的字符串拼接操作时,StringBuilder 是性能最佳的选择。
示例代码:
public class StringBuilderExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("World");
String result = sb.toString();
System.out.println(result); // 输出: Hello World
// 链式调用
StringBuilder sb2 = new StringBuilder("Start");
sb2.append(" ").append("Chain").append(" Call");
System.out.println(sb2.toString()); // 输出: Start Chain Call
}
}
优点:
- 高性能:所有操作都在同一个
StringBuilder对象上进行,避免了创建大量中间字符串对象,内存占用低,速度快。 - 线程不安全:由于没有同步开销,它的性能比
StringBuffer更好,在单线程环境下,应优先使用StringBuilder。
使用 StringBuffer
StringBuffer 是 Java 1.0 就引入的类,与 StringBuilder 功能完全相同,也是一个可变的字符序列。

示例代码:
public class StringBufferExample {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
sb.append("Hello");
sb.append(" ");
sb.append("World");
String result = sb.toString();
System.out.println(result); // 输出: Hello World
}
}
优点与缺点:
- 线程安全:
StringBuffer的所有方法都是synchronized的,因此是线程安全的,这意味着在多线程环境下,可以安全地使用StringBuffer进行并发修改。 - 性能较低:由于同步带来的开销,
StringBuffer的性能通常比StringBuilder差。 - 使用场景:只有在明确需要线程安全的字符串拼接操作时,才应使用
StringBuffer,在绝大多数单线程场景下,StringBuilder是更好的选择。
使用 String.join() (Java 8+)
如果你需要连接一个字符串数组或集合,并且它们之间有一个共同的分隔符,String.join() 是一个非常方便的方法。
示例代码:
import java.util.Arrays;
import java.util.List;
public class StringJoinExample {
public static void main(String[] args) {
// 连接字符串数组
String[] words = {"Hello", "World", "Java"};
String result1 = String.join(" ", words);
System.out.println(result1); // 输出: Hello World Java
// 连接集合
List<String> wordList = Arrays.asList("Java", "is", "awesome");
String result2 = String.join("-", wordList);
System.out.println(result2); // 输出: Java-is-awesome
}
}
优点:
- 代码简洁:语法非常清晰,可读性高。
- 功能明确:专门用于带分隔符的连接场景。
使用 String.format() 或 printf
当你需要将其他类型的数据(如数字、日期)格式化并拼接到字符串中时,String.format() 是一个很好的选择。
示例代码:
public class StringFormatExample {
public static void main(String[] args) {
String name = "Alice";
int age = 30;
// 使用 String.format()
String formattedString = String.format("My name is %s and I am %d years old.", name, age);
System.out.println(formattedString); // 输出: My name is Alice and I am 30 years old.
// 使用 printf (输出到控制台)
System.out.printf("Hello, %s! Your balance is: $%.2f%n", name, 1234.5678);
// 输出: Hello, Alice! Your balance is: $1234.57
}
}
优点:
- 格式化强大:可以轻松地将各种数据类型嵌入到字符串中,并控制其格式(如小数位数、对齐方式等)。
总结与选择建议
| 方法 | 线程安全 | 性能 | 适用场景 |
|---|---|---|---|
| / | 不适用 | 少量拼接时 OK,循环中差 | 少量、静态的字符串拼接,代码最简洁。 |
StringBuilder |
否 | 快 | 大量字符串拼接,单线程环境(首选)。 |
StringBuffer |
是 | 较慢 | 大量字符串拼接,多线程环境。 |
String.join() |
不适用 | 快 | 连接数组或集合,且元素间有共同分隔符。 |
String.format() |
不适用 | 较慢 | 需要将变量格式化后嵌入字符串的场景。 |
如何选择?
- 少量拼接(几次):直接用 ,简单明了。
- 循环中拼接或大量拼接:必须使用
StringBuilder。 - 多线程环境下的拼接:使用
StringBuffer(虽然很少见)。 - 拼接一个列表/数组,且需要分隔符:使用
String.join()。 - 需要格式化输出(如日志、消息):使用
String.format()或printf。
最佳实践:在现代 Java 开发中,StringBuilder 是进行字符串追加操作的首选工具,尤其是在性能敏感的代码中。

