今天在leetcode上做题的时候发现,实现字符串拼接的时候,用StringBuffer的append比String的+快很多。思考了一下这两者的差别。
我是初学者,有说错的还请大家指正!
首先得出String的+拼接的时间
public static void main(String[] args)
{
String str = "";
String s = "abcd";
long starttime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
{
str += s;
}
long stoptime = System.currentTimeMillis();
System.out.println(stoptime - starttime);
}
运行程序三次,得到的结果为 14726ms、14788ms、14930ms
姑且认为完成100000次拼接的时间为14800ms。
并且,在实验中发现,如果完成10000次拼接(十分之一规模)的时间是200ms左右,远小于上面时间的十分之一。
下面测试StringBuffer的append所用的时间
public static void main(String[] args)
{
StringBuffer str = new StringBuffer();
StringBuffer s = new StringBuffer("abcd");
long starttime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
{
str.append(s);
}
long stoptime = System.currentTimeMillis();
System.out.println(stoptime - starttime);
}
运行程序三次,得到的结果为16ms、15ms、15ms
姑且认为完成100000次append的时间为15ms。
同时发现,append的时间复杂度似乎是N。这一点不太确定。
由上可见用StringBuffer的append来完成 “字符串拼接“ 比String的拼接快很多,特别是在量大的情况下。
但是这是为什么呢?
因为String是字符串常量,而StringBuffer是变量。
也就是说String型的数据,一旦被创建是不可修改的,对其进行修改的话,会另外创建一个新的String,然后把数据复制过去,旧的就当垃圾处理掉了。这样一来,效率就及其低下了。
那么StringBuffer是怎么做的呢?我发现了这么一段源码:
/**
* Appends the specified string to this character sequence.
* <p>
* The characters of the {@code String} argument are appended, in
* order, increasing the length of this sequence by the length of the
* argument. If {@code str} is {@code null}, then the four
* characters {@code "null"} are appended.
* <p>
* Let <i>n</i> be the length of this character sequence just prior to
* execution of the {@code append} method. Then the character at
* index <i>k</i> in the new character sequence is equal to the character
* at index <i>k</i> in the old character sequence, if <i>k</i> is less
* than <i>n</i>; otherwise, it is equal to the character at index
* <i>k-n</i> in the argument {@code str}.
*
* @param str a string.
* @return a reference to this object.
*/
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
// Documentation in subclasses because of synchro difference
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
return appendNull();
int len = sb.length();
ensureCapacityInternal(count + len);
sb.getChars(0, len, value, count);
count += len;
return this;
}
粗略地看了一下代码,大概是StringBuffer型的数据的大小是可变的,在append时先增大其内存,然后利用getChars()将被append的数据复制过去。。
快就快在不用每一次都重新创建变量,每次复制的内容较少吧。。
另外,听说StringBuilder的效果更好。先留个坑,以后碰到了再研究。