在项目中拼接字符串有很多种方式,使用不当的话很容易对性能造成影响,下面就讲讲入如何优化项目中的字符拼接代码。
优化 +
拼接操作
最常用的就是 +
操作了,+
其实属于 Java
的语法糖:在编译阶段,编译器会将 +
操作编译为 StringBuilder
,比如下面的代码:
1 | String a = "Hello "; |
利用 javap
进行一下反编译,可以看到 String c = a + b
这行代码被编译为了 StringBuilder
的 append
操作:
hexo
因此,与 StringBuilder
一样,应该避免在代码中使用如下的字符拼接方式:
1 | String a = ""; |
上面这种优化方式是网上经常提到的,那么除了这种场景以外,项目中其他的 +
字符是否还需要优化呢?这个疑惑在这篇文章中找到了答案:java 字符串拼接的几种方式详解(执行效率及内存占用等对比):
由于编译器会帮助我们优化,那加号的字符串拼接操作可否认为等同 StringBuilder 的使用呢?
答案是这种认知是错误的,主要是以下两点原因:
- 如果加号拼接是多次分开操作的,其实相当于多次实例化了 StringBuilder 对象;
- StringBuilder 的构造方法有 4 个,加号拼接操作优化成调用 StringBuilder 的默认无参构造方法,和实际使用其它构造方法会有区别。
如果使用场景避免如上两个 case,那么其实两种方式是一样的。
结合上面的分析,说说我的个人理解。如果项目中的字符串拼接出现了如下的场景,那么需要使用 StringBuilder
来进行优化:
- 循环中使用
+
拼接字符串,或者+
是分多次进行拼接的。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 循环中拼接
String a = "";
for (int i = 0; i < 10; i++) {
// 每次都会new一个StringBuilder
a += i;
}
// 多次拼接
String s1 = "A";
String s2 = "B";
// new一个StringBuilder
String first = s1 + s2;
String s3 = "C";
// new第二个StringBuilder
String second = first + s3; +
拼接的字符串长度很长,会导致多次扩容操作。那么需要使用带参的StringBuilder
构造函数进行优化。1
2
3
4String s1 = "sdfghjklzxcvnmsdjsfjksfsfsjf";
String s2 = "sdjkjgdfjgldkdjldkjgldkgjdljkdgkdjgldjdglkdl";
// StringBuilder无参构造函数默认长度是16,在append()时若长度不够会进行扩容
String s3 = s1 + s2;
除上面说的两种情况外,其他的 +
拼接场景可以沿用。 +
本身就是 Java
的一个语法糖,如果性能不会受到影响,那就没有必要过度优化。
复用 StringBuilder
对象
另外,我们还可以利用 StringBuilder
的 setLength(0)
或 delete(0, length)
方法来优化循环中多次创建 StringBuilder
的代码,如下:
1 | List<String> list = new LinkedList<>(); |
setLength(0)
和 delete(0, length)
都可以清空 String
对象,区别是 delete()
操作多执行了一次 cp
数组拷贝操作,而 setLength()
只是重置了 count
,源码如下:
1 | // setLength() |
1 | // delete() |
对比实验见:StringBuffer清空操作delete和setLength的效率对比分析
参考文章
String、StringBuilder、StringBuffer