本來String類已經能夠完成字串操作的所有功能,為何Java又提供了專門的StringBuffer和StringBuilder呢?這要從String類的設計說起了,查看String的原始碼,發現其內部采用字符陣列保存字串,如下所示:
private final char value[];
可是問題在于,這個字符陣列被final修飾了,意味著陣列大小不可改變,若想將現有字串拼接一段字符形成新串(無論是加號拼接還是呼叫format方法),String類就無法擴充現有的字符陣列,只能重新生成新的String物件,然而在需要頻繁拼接字串的場合,不斷地重新生成String物件,這涉及到記憶體資料的反復銷毀和反復分配,無疑對程式性能產生巨大的影響,
為了解決頻繁拼接帶來的性能問題,一開始Java提供了StringBuffer類,其內部的value陣列是大小可變的,在拼接字串時無需重新生成StringBuffer物件,由此避免了物件創建與物件銷毀帶來的開銷,StringBuffer的拼接方法名叫append,因為該方法同時也回傳拼接后的StringBuffer物件,所以拼接多個字串時只需連續呼叫append即可,
不過Java把StringBuffer類設計成執行緒安全,它的append方法被synchronized修飾,表示這是個同步方法,既然是同步方法,那么呼叫之時就會先加鎖,等呼叫結束再解鎖,該設計的意圖是讓StringBuffer類更加健壯,但是拼接字串幾乎不存在多執行緒并發的場景,絕大多數情況都是按順序拼接,誰會腦袋抽筋中途插隊拼接呢?于是這個鎖同步設計形同雞肋,
鑒于加解鎖也會帶來額外的性能損耗,因此JDK1.5又增加了StringBuilder類,該類的實作方式與StringBuffer類大同小異,主要區別在于StringBuilder類的append方法去掉了synchronized修飾,從而省去了無謂的加解鎖操作,
下面通過實際代碼演示一下StringBuffer、StringBuilder和String三者在頻繁拼接時候的性能表現,每種物件分別拼接字串199999次:
public static void main(String[] argv) {
testBuffer(199999);
testBuilder(199999);
testString(199999);
}
// 測驗StringBuffer的字串拼接
private static void testBuffer(int count) {
long beginTime = System.currentTimeMillis();
StringBuffer buffer = new StringBuffer("");
for (int i=0; i<=count; i++) {
buffer.append("a");
}
long endTime = System.currentTimeMillis();
String costTime = String.format("%.3fs", (endTime-beginTime)/1000.0);
System.out.println("testBuffer cost "+costTime);
}
// 測驗StringBuilder的字串拼接
private static void testBuilder(int count) {
long beginTime = System.currentTimeMillis();
StringBuilder builder = new StringBuilder("");
for (int i=0; i<=count; i++) {
builder.append("a");
}
long endTime = System.currentTimeMillis();
String costTime = String.format("%.3fs", (endTime-beginTime)/1000.0);
System.out.println("testBuilder cost "+costTime);
}
// 測驗String的字串拼接
private static void testString(int count) {
long beginTime = System.currentTimeMillis();
String str = "";
for (int i=0; i<=count; i++) {
str += "a";
}
long endTime = System.currentTimeMillis();
String costTime = String.format("%.3fs", (endTime-beginTime)/1000.0);
System.out.println("testString cost "+costTime);
}
運行測驗代碼,觀察到如下所示的結果日志:
testBuffer cost 0.022s testBuilder cost 0.010s testString cost 13.865s
可見StringBuilder耗時最短,StringBuffer其次當然差距也不大,String耗時最長并且差距顯著增大,上述案例說明,在大量拼接字串的場合,采取StringBuilder實作是最經濟的,
更多Java技術文章參見《Java開發筆記(序)章節目錄》
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/499251.html
標籤:其他
上一篇:沒那么簡單的單例模式
