String和StringBuffer的區(qū)別,網(wǎng)上資料可以說是數(shù)不勝數(shù),但是看到這篇文章,感覺里面做的小例子很有代表性,所以轉(zhuǎn)一下,并自己做了一點(diǎn)總結(jié)。
在java中有3個(gè)類來負(fù)責(zé)字符的操作。
1.Character 是進(jìn)行單個(gè)字符操作的,
2.String 對一串字符進(jìn)行操作。不可變類。
3.StringBuffer 也是對一串字符進(jìn)行操作,但是可變類。
String:
是對象不是原始類型.
為不可變對象,一旦被創(chuàng)建,就不能修改它的值.
對于已經(jīng)存在的String對象的修改都是重新創(chuàng)建一個(gè)新的對象,然后把新的值保存進(jìn)去.
String 是final類,即不能被繼承.
StringBuffer:
是一個(gè)可變對象,當(dāng)對他進(jìn)行修改的時(shí)候不會像String那樣重新建立對象
它只能通過構(gòu)造函數(shù)來建立,
StringBuffer sb = new StringBuffer();
note:不能通過付值符號對他進(jìn)行付值.
sb = "welcome to here!";//error
對象被建立以后,在內(nèi)存中就會分配內(nèi)存空間,并初始保存一個(gè)null.向StringBuffer
中付值的時(shí)候可以通過它的append方法.
sb.append("hello");
字符串連接操作中StringBuffer的效率要比String高:
String str = new String("welcome to ");
str += "here";
的處理步驟實(shí)際上是通過建立一個(gè)StringBuffer,讓侯調(diào)用append(),最后
再將StringBuffer toSting();
這樣的話String的連接操作就比StringBuffer多出了一些附加操作,當(dāng)然效率上要打折扣.
并且由于String 對象是不可變對象,每次操作Sting 都會重新建立新的對象來保存新的值.
這樣原來的對象就沒用了,就要被垃圾回收.這也是要影響性能的.
看看以下代碼:
將26個(gè)英文字母重復(fù)加了5000次,
- String tempstr = "abcdefghijklmnopqrstuvwxyz";
- int times = 5000;
- long lstart1 = System.currentTimeMillis();
- String str = "";
- for (int i = 0; i < times; i++) {
- str += tempstr;
- }
- long lend1 = System.currentTimeMillis();
- long time = (lend1 - lstart1);
- System.out.println(time);
可惜我的計(jì)算機(jī)不是超級計(jì)算機(jī),得到的結(jié)果每次不一定一樣一般為 46687左右。
也就是46秒。
我們再看看以下代碼
- String tempstr = "abcdefghijklmnopqrstuvwxyz";
- int times = 5000;
- long lstart2 = System.currentTimeMillis();
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < times; i++) {
- sb.append(tempstr);
- }
- long lend2 = System.currentTimeMillis();
- long time2 = (lend2 - lstart2);
- System.out.println(time2);
得到的結(jié)果為 16 有時(shí)還是 0
所以結(jié)論很明顯,StringBuffer 的速度幾乎是String 上萬倍。當(dāng)然這個(gè)數(shù)據(jù)不是很準(zhǔn)確。因?yàn)檠h(huán)的次數(shù)在100000次的時(shí)候,差異更大。不信你試試。
根據(jù)上面所說:
str += "here";
的處理步驟實(shí)際上是通過建立一個(gè)StringBuffer,讓侯調(diào)用append(),最后
再將StringBuffer toSting();
所以str += "here";可以等同于
StringBuffer sb = new StringBuffer(str);
sb.append("here");
str = sb.toString();
所以上面直接利用"+"來連接String的代碼可以基本等同于以下代碼
- String tempstr = "abcdefghijklmnopqrstuvwxyz";
- int times = 5000;
- long lstart2 = System.currentTimeMillis();
- String str = "";
- for (int i = 0; i < times; i++) {
- StringBuffer sb = new StringBuffer(str);
- sb.append(tempstr);
- str = sb.toString();
- }
- long lend2 = System.currentTimeMillis();
- long time2 = (lend2 - lstart2);
- System.out.println(time2);
平均執(zhí)行時(shí)間為46922左右,也就是46秒。
總結(jié): 如果在程序中需要對字符串進(jìn)行頻繁的修改連接操作的話.使用StringBuffer性能會更高
===========================================================================================
為什么會出現(xiàn)那么多比較String和StringBuffer的文章?
原因在于當(dāng)改變字符串內(nèi)容時(shí),采用StringBuffer能獲得更好的性能。既然是為了獲得更好的性能,那么采用StringBuffer能夠獲得最好的性能嗎?
答案是NO!
為什么?
如果你讀過《Think in Java》,而且對里面描述HashTable和HashMap區(qū)別的那部分章節(jié)比較熟悉的話,你一定也明白了原因所在。對,就是支持線程同步保證線程安全而導(dǎo)致性能下降的問題。HashTable是線程安全的,很多方法都是synchronized方法,而HashMap不是線程安全的,但其在單線程程序中的性能比HashTable要高。StringBuffer和StringBuilder類的區(qū)別也在于此,新引入的StringBuilder類不是線程安全的,但其在單線程中的性能比StringBuffer高。如果你對此不太相信,可以試試下面的例子:
package com.hct.test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @author: chengtai.he
* @created:2009-12-9 上午09:59:57
*/
public class StringBuilderTester {
private static final String base = " base string. ";
private static final int count = 2000000;
public static void stringTest() {
long begin, end;
begin = System.currentTimeMillis();
String test = new String(base);
for (int i = 0; i < count/100; i++) {
test = test + " add ";
}
end = System.currentTimeMillis();
System.out.println((end - begin)
+ " millis has elapsed when used String. ");
}
public static void stringBufferTest() {
long begin, end;
begin = System.currentTimeMillis();
StringBuffer test = new StringBuffer(base);
for (int i = 0; i < count; i++) {
test = test.append(" add ");
}
end = System.currentTimeMillis();
System.out.println((end - begin)
+ " millis has elapsed when used StringBuffer. ");
}
public static void stringBuilderTest() {
long begin, end;
begin = System.currentTimeMillis();
StringBuilder test = new StringBuilder(base);
for (int i = 0; i < count; i++) {
test = test.append(" add ");
}
end = System.currentTimeMillis();
System.out.println((end - begin)
+ " millis has elapsed when used StringBuilder. ");
}
public static String appendItemsToStringBuiler(List list) {
StringBuilder b = new StringBuilder();
for (Iterator i = list.iterator(); i.hasNext();) {
b.append(i.next()).append(" ");
}
return b.toString();
}
public static void addToStringBuilder() {
List list = new ArrayList();
list.add(" I ");
list.add(" play ");
list.add(" Bourgeois ");
list.add(" guitars ");
list.add(" and ");
list.add(" Huber ");
list.add(" banjos ");
System.out.println(StringBuilderTester.appendItemsToStirngBuffer(list));
}
public static String appendItemsToStirngBuffer(List list) {
StringBuffer b = new StringBuffer();
for (Iterator i = list.iterator(); i.hasNext();) {
b.append(i.next()).append(" ");
}
return b.toString();
}
public static void addToStringBuffer() {
List list = new ArrayList();
list.add(" I ");
list.add(" play ");
list.add(" Bourgeois ");
list.add(" guitars ");
list.add(" and ");
list.add(" Huber ");
list.add(" banjos ");
System.out.println(StringBuilderTester.appendItemsToStirngBuffer(list));
}
public static void main(String[] args) {
stringTest();
stringBufferTest();
stringBuilderTest();
addToStringBuffer();
addToStringBuilder();
}
}
上面的程序結(jié)果如下:
5266 millis has elapsed when used String.
375 millis has elapsed when used StringBuffer.
281 millis has elapsed when used StringBuilder.
I play Bourgeois guitars and Huber banjos
I play Bourgeois guitars and Huber banjos
從上面的結(jié)果來看,這三個(gè)類在單線程程序中的性能差別一目了然,采用String對象時(shí),即使運(yùn)行次數(shù)僅是采用其他對象的1/100,其執(zhí)行時(shí)間仍然比其他對象高出25倍以上;而采用StringBuffer對象和采用StringBuilder對象的差別也比較明顯,前者是后者的1.5倍左右。由此可見,如果我們的程序是在單線程下運(yùn)行,或者是不必考慮到線程同步問題,我們應(yīng)該優(yōu)先使用StringBuilder類;當(dāng)然,如果要保證線程安全,自然非StringBuffer莫屬了。
除了對多線程的支持不一樣外,這兩個(gè)類的使用幾乎沒有任何差別,上面的例子就是個(gè)很好的說明。appendItemsToStringBuiler和appendItemsToStirngBuffer兩個(gè)方法除了采用的對象分別為StringBuilder和StringBuffer外,其他完全相同,而效果也完全相同。