初始长度很重要
StringBuilder
的内部有一个char[]
,不同的append()
就是不断的往char[]
里填东西的过程。
new StringBuilder()
时char[]
的默认长度为16,超过就用System.arraycopy
成倍复制扩容。
这样一来有数组拷贝的成本,二来原来的char[]
也白白浪费了,要被GC
掉。
所以,合理设置一个初始值是很重要的。
一种长度设置的思路,在
append()
的时候,不急着往char[]
里塞东西,而是先拿一个String[]
把它们都存起来,到了最后才把所有String
的length
加起来,构造一个合理长度的StringBuilder
。
但是,还是会浪费一倍的char[]
因为:
return new String(value, 0, count);
String
的构造函数会用System.arraycopy()
复制一次传入的char[]
来保证安全性及不可变性,这样StringBuilder
里的char[]
就白白牺牲掉了。
为了不浪费这些char[]
,可以重用StringBuilder
。
重用StringBuilder
public StringBuilder getStringBuilder() {
sb.setLength(0);
return sb;
}
为了避免并发冲突,这个Holder
一般设为ThreadLocal
。
+和StringBuilder
String str = "hello " + user.getName();
这一句经过javac
编译后的效果,的确等价于使用StringBuilder
,但没有设定长度。
但是,如果像下面这样:
String str = "hello ";
str = str + user.getName();
每一条语句,都会生成一个新的StringBuilder
,这样这里就有了两个StringBuilder
,性能就完全不一样了。
保险起见,还是继续自己用StringBuilder
并设定好长度。
private static final ThreadLocal<StringBuilderHelper> threadLocalStringBuilderHolder = new ThreadLocal<StringBuilderHelper>() {
protected StringBuilderHelper initialValue() {
return new StringBuilderHelper(256);
}
}
StringBuilder sb = threadLocalStringBuilderHolder.get().resetAndGetStringBuilder();
StringBuidlerHolder
public class StringBuilderHolder {
private final StringBuilder sb;
public StringBuilderHolder(int capacity) {
sb = new StringBuidler(capacity);
}
public StringBuilder resetAndGetStringBuilder() {
sb.setLength(0);
return sb;
}
}