淺談StringBuilder類的capacity()方法和length()方法的一些小坑
今天在做項目的過程中遇見一個StringBuilder.delete()刪除得不到自己期望結果問題,一個截取字符串的問題,總得不到自己所期望的答案:
問題如下:
stringBuilder.delete(stringBuilder.capacity() - 5, stringBuilder.capacity());
此句代碼要麼報錯,要麼多刪,要麼少刪,也有時候正確。也有時候得不到自己所想要的字符串;
簡單的測試capacity()方法和length()方法的區別如下:
StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("abcdefgh2321"); System.out.println("length:" + stringBuilder.length()); System.out.println("capacity:" + stringBuilder.capacity()); System.out.println("length截取:" + stringBuilder.delete(stringBuilder.length() - 3,stringBuilder.length())); System.out.println("capacity截取:" + stringBuilder.delete(stringBuilder.capacity() - 7,stringBuilder.capacity())); System.out.println("capacity截取:" + stringBuilder.delete(stringBuilder.capacity() - 5,stringBuilder.capacity()));
代碼如上:
輸出:
最後查看源碼,
StringBuilder類繼承於AbstractStringBuilder抽象類:
在AbstractStringBuilder抽象類中,放入進去的字符串存儲於char[] value 數組中,count為存進去的字符數目,
使用capacity()方法得到的為 value數組的長度,length()方法得到的為count,也就是字符串的實際長度。
在初始化StringBuilder時候,也就是new StringBuilder()時候,會初始化一個char[16]大小的char數據來存儲字符串,如果字符串增加之後,會進行擴容。
當然,如果 new StringBuilder(“213123”);會在字符串的長度的增加16作為初始數組char[] value的大小,
最後:
希望大傢在使用capacity()方法和length()方法時要註意選擇:否則會導致意想不到的坑。
StringBuilder初始化的大小對性能的影響
StringBuilder 是一個可以動態增加自身數據長度的類,其默認長度(capacity屬性)為16。
它有一個構造函數,可以指定其容器長度。當數據量小時,指定長度意義不大,但是當數據量比較大時,指定長度會對性能產生顯著影響。
本文通過一個小示例驗證其對性能產生的影響
代碼如下:
public class StringBuilderTest { public static void main(String[] args) throws Exception { // 前兩行分別是獲取運行次數和StringBuilder的初始化長度 int times = args.length > 0 ? Integer.parseInt(args[0]) : 100; int length = args.length > 1 ? Integer.parseInt(args[1]) : 0; // 運行 times 次的 test(length)方法 long t1 = System.currentTimeMillis(); for (int i = 0; i < times; i++) test(length); long t2 = System.currentTimeMillis(); // 輸出單次運行時間 System.out.printf("Time taken: %d ms.\n", (t2 - t1) / times); } // 這個方法隻是單純地做循環向StringBuilder中添加數據。 static int test(int length) { StringBuilder sb = new StringBuilder(length); for (int i = 0; i < 10000000; i++) sb.append(i + ""); return sb.length(); } }
以下是編碼後,分配2GB內存,在控制臺測試運行100次的運行結果。
$ java -Xmx2g -Xms2g StringBuilderTest 100 0
Time taken: 273 ms.
$ java -Xmx2g -Xms2g StringBuilderTest 100 73000000
Time taken: 205 ms.
性能差距約為30%
結論
當在使用StringBuilder處理大數據的時候,如果我們可以預知或者以很小的性能損失就能獲得數據的大小時,提前指定StringBuilder的長度可顯著提高處理速度。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Java有哪些操作字符串的類?區別在哪?
- Java常用類之字符串相關類使用詳解
- 簡單聊聊C#字符串構建利器StringBuilder
- Java StringBuilder的用法示例
- JAVA基礎類庫之String類,StringBuffer類和StringBuilder類