StringBuider 在什么條件下、如何使用效率更高_相關技巧

來源:腳本之家  責任編輯:小易  

這個東西的存在看似很沒有道理但是其實是這樣的.舉個例子:你拼字符串一般是怎么拼呢?String city="上海;String a="您好,歡迎來到"+city;是吧?但是這樣做的意思是什么?電腦會在內存中令開辟一塊內存空間,實例化一個新的String類來保存它.如果有大量字符串操作,這么做肯定是很消耗內存的.并且效率低下所以,StringBuilder出現了.他不能+,但是它有Append和Remove等函數來實現拼接和刪除字符串.在操作字符串的時候,他不會再重新實例化一個類這樣可以節省內存,提高效率。當然,他還有N多函數.可以對字符串作各種操作.可以說是一個字符串工具箱!你還是查一下MSDN吧(JAVA里也有這個.類似的還有StringBuffer參見JAVA API)www.anxorj.tw防采集請勿采集本網。

引言

都說 StringBuilder 在處理字符串拼接上效率要強于 String,但有時候我們的理解可能會存在一定的偏差。最近我在測試數據導入效率的時候就發現我以前對 StringBuilder 的部分理解是錯誤的。 后來我通過實踐測試 + 找原理 的方式搞清楚了這塊的邏輯,F在將過程分享給大家

using system.text;反正就這樣。你自己加上這個命名空間就行了

測試用例

stringBuilder很不錯的,完全可以替代string,最主要的是它的效率高 必須先實例化一個 stringBuilder sBuilder=new stringBuilder();您可以拼接執行SQL語句,易于閱讀 sBuilder.Append(\"select*

我們的代碼在循環中拼接字符串一般有兩種情況

StringBuilder 字符串變量(非線程安全) 簡要的說,String 類型和 StringBuffer 類型的主要性能區別其實在于 String 是不可變的對象,因此在每次對 String 類型進行改變的時候其實都等同于生成了一個新的

第一種就是每次循環將對象中的幾個字段拼接成一個新字段,再賦值給對象第二種操作是在循環外創建一個字符串對象,每次循環向該字符串拼接新的內容。循環結束后得到拼接好的字符串

對于這兩種情況,我創建了兩個對照組

第一組:

在每次 For 循環中拼接字符串,即拼即用、用完即毀。分別使用 String 和 StringBuilder 拼接

/** * 循環內 String 拼接字符串,一次循環后銷毀 */ public static void useString(){ for (int i = 0; i < CYCLE_NUM_BIGGER; i++) { String str = str1 + i + str2 + i + str3 + i + str4 ; } } /** * 循環內 使用 StringBuilder 拼接字符串,一次循環后銷毀 */ public static void useStringBuilder(){ for (int i = 0; i < CYCLE_NUM_BIGGER; i++) { StringBuilder sb = new StringBuilder(); String s = sb.append(str1).append(i).append(str2).append(i).append(str3).append(i).append(str4).toString(); } }

第二組:

多次 For 循環拼接一個字符串,循環結束后使用字符串,使用后由垃圾回收器回收。也是分別使用 String 和 StringBuilder 拼接

/** * 多次循環拼接成一個字符串 用 String */ public static void useStringSpliceOneStr (){ String str = ""; for (int i = 0; i < CYCLE_NUM_LOWER; i++) { str += str1 + str2 + str3 + str4 + i; } } /** * 多次循環拼接成一個字符串 用 StringBuilder */ public static void useStringBuilderSpliceOneStr(){ StringBuilder sb = new StringBuilder(); for (int i = 0; i < CYCLE_NUM_LOWER; i++) { sb.append(str1).append(str2).append(str3).append(str4).append(i); } }

為了保證測試質量,在每個測試項目進行前。線程休息 2s,之后空跑 5 次熱身。最后執行 5 次求平均時間的方式計算時間

public static int executeSometime(int kind, int num) throws InterruptedException { Thread.sleep(2000); int sum = 0; for (int i = 0; i < num + 5; i++) { long begin = System.currentTimeMillis(); switch (kind){ case 1: useString(); break; case 2: useStringBuilder(); break; case 3: useStringSpliceOneStr(); break; case 4: useStringBuilderSpliceOneStr(); break; default: return 0; } long end = System.currentTimeMillis(); if(i > 5){ sum += (end - begin); } } return sum / num; }

主方法

public class StringTest { public static final int CYCLE_NUM_BIGGER = 10_000_000; public static final int CYCLE_NUM_LOWER = 10_000; public static final String str1 = "張三"; public static final String str2 = "李四"; public static final String str3 = "王五"; public static final String str4 = "趙六"; public static void main(String[] args) throws InterruptedException { int time = 0; int num = 5; time = executeSometime(1, num); System.out.println("String拼接 "+ CYCLE_NUM_BIGGER +" 次," + num + "次平均時間:" + time + " ms"); time = executeSometime(2, num); System.out.println("StringBuilder拼接 "+ CYCLE_NUM_BIGGER +" 次," + num + "次平均時間:" + time + " ms"); time = executeSometime(3, num); System.out.println("String拼接單個字符串 "+ CYCLE_NUM_LOWER +" 次," + num + "次平均時間:" + time + " ms"); time = executeSometime(4, num); System.out.println("StringBuilder拼接單個字符串 "+ CYCLE_NUM_LOWER +" 次," + num + "次平均時間:" + time + " ms"); }}

測試結果

測試結果如下

結果分析

第一組

10_000_000 次循環拼接,在循環內使用 String 和 StringBuilder 的效率是一樣的!為什么呢?

使用 javap -c StringTest.class 反編譯查看兩個方法編譯后的文件:

可以發現 String 方法拼接字符串編譯器優化后使用的就是 StringBuilder、因此用例1 和用例2 的效率是一樣的。

第二組

第二組的結果就是大家喜聞樂見的了,由于 10_000_000 次循環String 拼接實在太慢所以我采用了 10_000 次拼接來分析。

分析用例3:雖然編譯器會對 String 拼接做優化,但是它每次在循環內創建 StringBuilder 對象,在循環內銷毀。下次循環他有創建。相比較用例4在循環外創建,多了 n 次 new 對象、銷毀對象的操作、n - 1 次將 StringBuilder 轉換成 String 的操作 。效率低也是理所應當了。

擴展

第一組的測試還有一種寫法:

/** * 循環內 使用 StringBuilder 拼接字符串,一次循環后銷毀 */ public static void useStringBuilderOut(){ StringBuilder sb = new StringBuilder(); for (int i = 0; i < CYCLE_NUM_BIGGER; i++) {// sb.setLength(0); sb.delete(0, sb.length()); String s = sb.append(str1).append(i).append(str2).append(i).append(str3).append(i).append(str4).toString(); } }

循環外創建 StringBuilder 每次循環開始的時候清空 StringBuilder 的內容然后拼接。這種寫法無論使用 sb.setLength(0); 還是 sb.delete(0, sb.length()); 效率都比直接在循環內使用 String / StringBuilder 慢。奈何才疏學淺我一直想不明白為什么他慢。我猜測是 new 對象的速度比重置長度慢,于是這樣測試了以下:

public static void createStringBuider() { for (int i = 0; i < CYCLE_NUM_BIGGER; i++) { StringBuilder sb = new StringBuilder(); } } public static void cleanStringBuider() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < CYCLE_NUM_BIGGER; i++) { sb.delete(0, sb.length()); } }

但是結果是 cleanStringBuider 更快。讓我摸不著頭腦

如果有大神看到希望可以幫忙分析分析

結論

編譯器會將 String 拼接優化成使用 StringBuilder,但是還是有一些缺陷的。主要體現在循環內使用字符串拼接,編譯器不會創建單個 StringBuilder 以復用

對于多次循環內拼接一個字符串的需求:StringBuilder 很快,因為其避免了 n 次 new 對象、銷毀對象的操作,n - 1 次將 StringBuilder 轉換成 String 的操作

StringBuilder 拼接不適用于循環內每次拼接即用的操作方式。因為編譯器優化后的 String 拼接也是使用 StringBuilder 兩者的效率一樣。后者寫起來還方便...

到此這篇關于StringBuider 在什么條件下、如何使用效率更高?的文章就介紹到這了,更多相關StringBuider如何使用效率更高內容請搜索真格學網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持真格學網!

簡要的說,String 類型和 StringBuffer 類型的主要性能區別其實在于 String 是不可變的對象(為什么?問問 Java 的設計者吧,為什么 String 不是原生類型呢?因此在每次對 String 類型進行改變的時候其實都等同于生成了一個新的 String 對象,然后將指針指向新的 String 對象,所以經常改變內容的字符串最好不要用 String,因為每次生成對象都會對系統性能產生影響,特別當內存中無引用對象多了以后,JVM 的 GC 就會開始工作,那速度是一定會相當慢的。這里嘗試舉個不是很恰當的例子:String S1=“abc”;For(int I=0;I;I+)/For 模擬程序的多次調用{S1+“def”;S1=“abc”;}如果是這樣的話,到這個 for 循環完畢后,如果內存中的對象沒有被 GC 清理掉的話,內存中一共有 2 萬多個了,驚人的數目,而如果這是一個很多人使用的系統,這樣的數目就不算很多了,所以大家使用的時候一定要小心。而如果是使用 StringBuffer 類則結果就不一樣了,每次結果都會對 StringBuffer 對象本身進行操作,而不是生成新的對象,再改變對象引用。所以在一般情況下我們推薦使用 StringBuffer,特別是字符串對象經常改變的情況下。而在某些特別情況下,String 對象的字符串拼接其實是被 JVM 解釋成了 StringBuffer 對象的拼接,所以這些時候 String 對象的速度并不會比 StringBuffer 對象慢,而特別是以下的字符串對象生成中,String 效率是遠要比 StringBuffer 快的:String S1=“This is only a”+“simple”+“test”;StringBuffer Sb=new StringBuilder(“This is only a”).append(“simple”).append(“test”);你會很驚訝的發現,生成 String S1 對象的速度簡直太快了,而這個時候 StringBuffer 居然速度上根本一點都不占優勢。其實這是 JVM 的一個把戲,在 JVM 眼里,這個String S1=“This is only a”+“simple”+“test”;其實就是:String S1=“This is only a simple test”;所以當然不需要太多的時間了。但大家這里要注意的是,如果你的字符串是來自另外的 String 對象的話,速度就沒那么快了,譬如:String S2=“This is only a”;String S3=“simple”;String S4=“test”;String S1=S2+S3+S4;這時候 JVM 會規規矩矩的按照原來的方式去做,S1 對象的生成速度就不像剛才那么快了,一會兒我們可以來個測試作個驗證。由此我們得到第一步結論:在大部分情況下 StringBuffer>String而 StringBuilder 跟他們比又怎么樣呢?先簡單介紹一下,StringBuilder 是 JDK5.0 中新增加的一個類,它跟 StringBuffer 的區別看下面的介紹(來源 JavaWorld):Java.lang.StringBuffer 線程安全的可變字符序列。類似于 String 的字符串緩沖區,但不能修改?蓪⒆址彌_區安全地用于多個線程?梢栽诒匾獣r對這些方法進行同步,因此任意特定實例上的所有操作就好像是以串行順序發生的,該順序與所涉及的每個線程進行的方法調用順序一致。每個字符串緩沖區都有一定的容量。只要字符串緩沖區所包含的字符序列的長度沒有超出此容量,就無需分配新的內部緩沖區數組。如果內部緩沖區溢出,則此容量自動增大。從 JDK 5.0 開始,為該類增添了一個單個線程使用的等價類,即 StringBuilder。與該類相比,通常應該優先使用 StringBuilder 類,因為它支持所有相同的操作,但由于它不執行同步,所以速度更快。但是如果將 StringBuilder 的實例用于多個線程是不安全的。需要這樣的同步,則建議使用 StringBuffer。這樣說估計大家都能明白他們之間的區別了,那么下面我們再做一個一般性推導:在大部分情況下 StringBuilder>StringBuffer因此,根據這個不等式的傳遞定理:在大部分情況下 StringBuilder>StringBuffer>String既然有這樣的推導結果了,我們做個測試驗證一下:測試代碼如下:public class testssb {Creates a new instance of testssb*/final static int ttime=10000;測試循環次數public testssb(){}public void test(String s){long begin=System.currentTimeMillis();for(int i=0;i;i+){s+"add;}long over=System.currentTimeMillis();System.out.println("操作"+s.getClass().getName()+"類型使用的時間為:"+(over-begin)+"毫秒");}public void test(StringBuffer s){long begin=System.currentTimeMillis();for(int i=0;i;i+){s.append("add");}long over=System.currentTimeMillis();System.out.println("操作"+s.getClass().getName()+"類型使用的時間為:"+(over-begin)+"毫秒");}public void test(StringBuilder s){long begin=System.currentTimeMillis();for(int i=0;i;i+){s.append("add");}long over=System.currentTimeMillis();System.out.println("操作"+s.getClass().getName()+"類型使用的時間為:"+(over-begin)+"毫秒");}對 String 直接進行字符串拼接的測試public void test2(){String s2="abadf;long begin=System.currentTimeMillis();for(int i=0;i;i+){String s=s2+s2+s2;}long over=System.currentTimeMillis();System.out.println("操作字符串對象引用相加類型使用的時間為:"+(over-begin)+"毫秒");}public void test3(){long begin=System.currentTimeMillis();for(int i=0;i;i+){String s="abadf"+"abadf"+"abadf;}long over=System.currentTimeMillis();System.out.println("操作字符串相加使用的時間為:"+(over-begin)+"毫秒");}public static void main(String[]args){String s1="abc;StringBuffer sb1=new StringBuffer("abc");StringBuilder sb2=new StringBuilder("abc");testssb t=new testssb();t.test(s1);t.test(sb1);t.test(sb2);t.test2();t.test3();}}以上代碼在 NetBeans 5.0 IDE/JDK1.6 上編譯通過,循環次數 ttime 為 10000 次的測試結果如下:操作 java.lang.String 類型使用的時間為:4392 毫秒操作 java.lang.StringBuffer 類型使用的時間為:0 毫秒操作 java.lang.StringBuilder 類型使用的時間為:0 毫秒操作字符串對象引用相加類型使用的時間為:15 毫秒操作字符串相加使用的時間為:0 毫秒好像還看不出 StringBuffer 和 StringBuilder 的區別,把 ttime 加到 30000 次看看:操作 java.lang.String 類型使用的時間為:53444 毫秒操作 java.lang.StringBuffer 類型使用的時間為:15 毫秒操作 java.lang.StringBuilder 類型使用的時間為:15 毫秒操作字符串對象引用相加類型使用的時間為:31 毫秒操作字符串相加使用的時間為:0 毫秒StringBuffer 和 StringBuilder 的性能上還是沒有太大的差異,再加大到 100000 看看,這里就不加入對 String 類型的測試了,因為對 String 類型這么大數據量的測試會很慢滴…操作 java.lang.StringBuffer 類型使用的時間為:31 毫秒操作 java.lang.StringBuilder 類型使用的時間為:16 毫秒能看出差別了,但其中有多次的測試結果居然是 StringBuffer 比 StringBuilder 快,再加大一些到 1000000 看看(應該不會當機吧?操作 java.lang.StringBuffer 類型使用的時間為:265 毫秒操作 java.lang.StringBuilder 類型使用的時間為:219 毫秒有些少區別了,而且結果很穩定,再大點看看,ttime=5000000:Exception in thread"main"java.lang.OutOfMemoryError:Java heap space·呵呵,算了,不去測試了,基本來說都是在性能上都是 StringBuilder>StringBuffer>String 的了內容來自www.anxorj.tw請勿采集。


  • 本文相關:
  • 深入解析java編程中的stringbuffer與stringbuider
  • 奇怪的回車換行問題
  • eclipse 格式化代碼時不換行與自動換行的實現方法
  • https的七個誤解
  • 漂流瓶推送需求的邏輯實現代碼
  • git里多種撤銷操作的最佳方法
  • json轉string與string轉json及判斷對象類型示例代碼
  • zend stdio8.0 快捷鍵匯總集合
  • 網站登錄持久化cookie方案
  • web 開發中遇到的utf-8編碼的問題總結
  • 30個提高web程序執行效率的好經驗分享
  • StringBuilder是什么類型???
  • StringBuilder是什么意思
  • string和stringbuilder的區別
  • StringBuilder是什么意思
  • c# stringbuilder 在哪個空間 怎么引用
  • stringBuilder怎么用?
  • java中的StringBuilder有什么用?
  • C#string和StringBuilder的區別
  • 網站首頁網頁制作腳本下載服務器操作系統網站運營平面設計媒體動畫電腦基礎硬件教程網絡安全javascriptasp.netphp編程ajax相關正則表達式asp編程jsp編程編程10000問css/htmlflex腳本加解密web2.0xml/rss網頁編輯器相關技巧安全相關網頁播放器其它綜合dart首頁深入解析java編程中的stringbuffer與stringbuider奇怪的回車換行問題eclipse 格式化代碼時不換行與自動換行的實現方法漂流瓶推送需求的邏輯實現代碼git里多種撤銷操作的最佳方法json轉string與string轉json及判斷對象類型示例代碼zend stdio8.0 快捷鍵匯總集合網站登錄持久化cookie方案web 開發中遇到的utf-8編碼的問題總結30個提高web程序執行效率的好經驗分享2019最新的pycharm激活碼(推薦)進制轉換算法原理(二進制 八進制eclipse 格式化代碼時不換行與自微信小程序設置http請求的步驟詳幾款開源的中文分詞系統十進制負數轉換為二進制、八進制從console.log說起(console.log詳url 長度有限制嗎?git 撤銷操作、刪除文件和恢復文gvim, gvim easy, gvim read-only 的簡單詳解https 加密完整過程git 教程之工作流程詳解git提交空目錄的方法算法系列15天速成 第七天 線性表【上】在命令行用 sort 進行排序的方法git ssh 配置及使用方法使用swipe方法模擬屏幕滑動與手勢密碼繪制網站程序員如何應對web標準對web開發人員有用的8個網站小結
    免責聲明 - 關于我們 - 聯系我們 - 廣告聯系 - 友情鏈接 - 幫助中心 - 頻道導航
    Copyright © 2017 www.anxorj.tw All Rights Reserved
    陕西快乐10分下载