1. 简介

Java 提供了多种用于 字符串拼接(String Concatenation) 的方法和类。

本文将深入探讨几种常用的方式,并指出一些常见的误区与不当实践。如果你已经对基础语法有所了解,那么可以直接跳过啰嗦的部分 ✅。

2. StringBuilder

先来说说 StringBuilder,这个类在 Java 字符串操作中扮演着非常重要的角色。

它内部维护一个可变字符数组,通过构造函数我们可以预设其初始容量(例如 100),这样可以避免频繁扩容带来的性能损耗:

StringBuilder stringBuilder = new StringBuilder(100);

stringBuilder.append("Baeldung");
stringBuilder.append(" is");
stringBuilder.append(" awesome");

assertEquals("Baeldung is awesome", stringBuilder.toString());

⚠️ 注意:StringBufferStringBuilder 的线程安全版本,但由于其构建模式,在多线程环境下并不推荐使用。虽然单个方法调用是线程安全的,但多个连续调用却不是 ❌。

3. 加号运算符(+)

加号 + 是最直观的拼接方式,适用于少量、静态的字符串拼接场景:

String myString = "The " + "quick " + "brown " + "fox...";

assertEquals("The quick brown fox...", myString);

但是要注意,这种方式在编译时会被转换为一系列 StringBuilder.append() 调用。因此,如果混用 +StringBuilder 拼接,容易造成代码风格混乱 ❌。

此外,在循环中大量使用 + 拼接字符串是非常低效的,因为每次拼接都会创建一个新的 String 对象,而 String 是不可变的 ⚠️。

4. String 类的方法

String 类本身也提供了多个拼接相关的方法。

4.1. String.concat()

concat() 方法是拼接字符串时最直接的选择之一。它可以链式调用,返回一个新的 String 实例:

String myString = "Both".concat(" fickle")
  .concat(" dwarves")
  .concat(" jinx")
  .concat(" my")
  .concat(" pig")
  .concat(" quiz");

assertEquals("Both fickle dwarves jinx my pig quiz", myString);

这种链式写法简洁明了,适合做固定结构的字符串组装。

4.2. String.format()

String.format() 则更加强大,支持格式化模板注入各种对象:

String myString = String.format("%s %s %.2f %s %s, %s...", "I",
  "ate",
  2.5056302,
  "blueberry",
  "pies",
  "oops");

assertEquals("I ate 2.51 blueberry pies, oops...", myString);

格式化字符串中的 %s%.2f 等占位符会自动替换为传入的参数,非常适合日志或输出语句。

4.3. String.join()(Java 8+)

从 Java 8 开始,String.join() 成为了拼接数组或集合中元素的好帮手。它接受一个分隔符,并自动将所有元素连接起来:

String[] strings = {"I'm", "running", "out", "of", "pangrams!"};

String myString = String.join(" ", strings);

assertEquals("I'm running out of pangrams!", myString);

相比手动拼接,这种方式更优雅、不易出错 ✅。

5. StringJoiner(Java 8+)

StringJoiner 是对 String.join() 功能的进一步封装,适用于需要动态添加字符串的场景:

StringJoiner fruitJoiner = new StringJoiner(", ");

fruitJoiner.add("Apples");
fruitJoiner.add("Oranges");
fruitJoiner.add("Bananas");

assertEquals("Apples, Oranges, Bananas", fruitJoiner.toString());

相比先构造数组再拼接,StringJoiner 更灵活,而且支持设置前缀和后缀,比如括号、引号等。

想深入了解的话可以看我们之前的文章《Java StringJoiner 详解》。

6. Arrays.toString()

说到数组,不得不提 Arrays.toString() 这个工具方法。它可以方便地打印数组内容,自动调用每个元素的 toString() 方法:

String[] myFavouriteLanguages = {"Java", "JavaScript", "Python"};

String toString = Arrays.toString(myFavouriteLanguages);

assertEquals("[Java, JavaScript, Python]", toString);

不过它的输出格式固定为 [元素1, 元素2, ...] 格式,无法自定义 ❌。

7. Collectors.joining()(Java 8+)

最后,如果你在使用 Stream API,那么 Collectors.joining() 就是你最好的朋友。它可以轻松把流中的元素拼接成一个字符串:

List<String> awesomeAnimals = Arrays.asList("Shark", "Panda", "Armadillo");

String animalString = awesomeAnimals.stream().collect(Collectors.joining(", "));

assertEquals("Shark, Panda, Armadillo", animalString);

这种方式不仅简洁,还能结合 filter、map 等流操作进行复杂的数据处理 ✅。

8. 总结

在这篇文章中,我们一起回顾了 Java 中多种字符串拼接方式的特点和适用场景:

方法 是否推荐 适用场景
+ 运算符 ⚠️ 少量拼接可用 静态文本拼接
StringBuilder ✅ 推荐 多次拼接、循环拼接
String.concat() ✅ 可用 简单链式拼接
String.format() ✅ 推荐 格式化输出
String.join() ✅ 推荐 数组/集合拼接
StringJoiner ✅ 推荐 动态拼接、带前后缀
Arrays.toString() ⚠️ 输出调试信息可用 打印数组
Collectors.joining() ✅ 推荐 流式拼接

如需获取文中示例代码,请访问 GitHub 仓库:https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-string-operations-2


原始标题:Concatenating Strings in Java | Baeldung