在 Java 中,字符串拼接是一个非常常见的操作,但也是影响性能的一个潜在问题点。Java 提供了以下字符串拼接方式:
-
使用
+
运算符 -
使用
StringBuilder
或StringBuffer
-
使用
String.concat()
方法 -
Java 8 中的
String.join()
和StringJoiner
每种方式在不同的场景下有各自的优势。我们来看一下这几种常见的字符串拼接方式的优缺点。
使用 +
运算符
这是最直观的拼接字符串的方法,非常简单易用。不过,当在循环中使用 +
拼接字符串时,每次拼接操作实际上都会创建一个新的 String
对象,这在大量或者复杂的字符串拼接操作中会导致内存使用和性能问题。
示例:
String result = ""; for (int i = 0; i < 1000; i++) {result += i; // 不推荐在循环中这样使用 }
你能写出上述示例代码编译后的伪代码吗?
上述代码在编译后,会被转换为使用 StringBuilder
的 append
方法,代码如下所示。
String result = ""; for (int i = 0; i < 1000; i++) {StringBuilder sb = new StringBuilder();sb.append(result);sb.append(i);result = sb.toString(); }
对于每次循环,编译器都会生成一个新的 StringBuilder
对象,然后调用 append
方法添加字符串。最后调用 toString
方法将 StringBuilder
的内容转换成 String
对象,并将其赋值给 result
变量。
这就是为什么在循环中使用这种字符串拼接方式是不推荐的,它会导致大量的临时 StringBuilder
对象的创建,以及对应的内存分配和回收,进而影响性能。
在单次循环中,会创建几个对象
-
每次循环中都会创建一个新的
StringBuilder
实例。 -
调用
StringBuilder
的toString()
方法,创建一个新的String
对象。 -
StringBuilder.append(int)
方法是优化过的,它将整数转换成字符序列并追加到内部的字符数组中,而不是创建一个代表整数的String
对象
因此,单次循环迭代中至少会创建两个对象。
使用 StringBuilder
或 StringBuffer
为了解决上述问题,可以使用 StringBuilder
(线程不安全,但性能较高)或 StringBuffer
(线程安全,但性能较低)进行字符串拼接。
推荐用法:
StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) {sb.append(i); } String result = sb.toString();
StringBuilder
内部持有一个可以动态扩展的字符数组。当我们添加内容时,它会先确保数组有足够能力承载新增的字符,然后将新字符串的内容复制过去。
使用 String.concat()
方法
这个方法用于将两个字符串连接在一起,但与使用 +
运算符类似,在循环中使用时也会产生多个字符串对象,因此同样不推荐在需要大量拼接的场景里使用它。
示例:
String hello = "Hello, ";String world = "world!";String result = hello.concat(world);
concat
方法在源码中是这样实现的:
public String concat(String str) {int otherLen = str.length();if (otherLen == 0) {return this;}int len = value.length;char buf[] = Arrays.copyOf(value, len + otherLen);str.getChars(buf, len);return new String(buf, true); }
这个方法首先确定两个字符串的总长度,创建一个新的字符数组并拷贝原有字符串的内容,然后拷贝第二个字符串的内容。最后,它会新建一个字符串实例来包裹这个字符数组。
Java 8 中的 String.join()
和 StringJoiner
Java 8 引入了 String.join()
方法和 StringJoiner
类,它们提供了一种更为高效和灵活的字符串拼接方式。
-
String.join()
可用于拼接数组或者集合中的字符串元素。 -
StringJoiner
可以在拼接时添加分隔符,前缀和后缀。
示例代码:
String[] strings = {"Java", "is", "cool"}; String message = String.join(" ", strings); // Output: Java is coolStringJoiner sj = new StringJoiner(", ", "{", "}"); sj.add("Java").add("Python").add("C++"); String result = sj.toString(); // Output: {Java, Python, C++}
总结:
-
对于简单的字符串拼接,使用
+
是方便的。 -
在处理大量数据或循环中,应优先考虑使用
StringBuilder
或StringBuffer
。 -
Java 8 的
String.join()
和StringJoiner
提供了更灵活的字符串处理能力,特别是在需要分隔符的情况下。