Java 中的 String、StringBuffer、StringBuilder 效率

Java 中的 String、StringBuffer、StringBuilder 效率

  • 《阿里巴巴 Java 開發手冊》中有一條是關於字符串拼接的建議:

123

  • 上面說使用 + 拼接會形成資源浪費,就是消耗內存,咱們就簡單模擬一下。

開幹

  • 使用 for 循環分別對String、StringBuffer、StringBuilder進行 10000 次字符串拼接,並統計耗時。

使用 String 拼接:java

static void StringTest() {
    String str = "";
    long begin = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        str += i;
    }
    long end = System.currentTimeMillis();
    long result = end- begin;
    System.out.println("String 拼接耗時:" + result);
}

使用 StringBuffer 拼接:編程

static void StringBufferTest() {
    StringBuffer str = new StringBuffer();
    long begin = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        str.append(i);
    }
    long end = System.currentTimeMillis();
    long result = end- begin;
    System.out.println("StringBuffer 拼接耗時:" + result);
}

使用 StringBilder 拼接:數組

static void StringBuilderTest() {
    StringBuilder str = new StringBuilder();
    long begin = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        str.append(i);
    }
    long end = System.currentTimeMillis();
    long result = end- begin;
    System.out.println("StringBuilder 拼接耗時:" + result);
}

結果

上面的代碼,同一電腦執行結果是(單位爲:Millis):安全

String 拼接耗時:23051
StringBuffer 拼接耗時:4
StringBuilder 拼接耗時:3
  • 結果代表,三者的執行效率是: StringBuilder > StringBuffer > String。其中 String 的耗時竟然是 StringBuffer 和 StringBuilder 的幾千倍。

接下來找下他們的效率快慢的緣由。併發

分析

關於 String

String 是不可擴展的字符串變量app

String 的工做方式

  • 如下舉個例子:
String str = "ABCD";
str += "加點東西";

咱們都知道 String 是不可擴展的字符串變量(內存地址不會變,建立了以後,該常量就不會改變了),當編譯器執行 String str = "ABCD"; 的時候,內存的方法區中會分配一個空間給常量 "ABCD", 棧中的變量 str 指向常量 "ABCD" 的內存地址,這時候完成 String str = "ABCD"; 這行代碼。ui

這時候若是咱們對 str 進行拼接操做,即執行 str += "加點東西"; , 那麼編譯器首先會在方法區的常量池尋找有沒有 "ABCD加點東西" 這個字符串常量(這時候確定是沒有該常量)。那麼編譯器會在常量池中從新開闢一塊空間給 "ABCD加點東西" (可是其實這個步驟,在底層實現的時候也是每次循環都會 StringBuilder對象,並調用其中的 append 方法進行拼接, 這也印證了爲何會 String 比 StringBuilder 效率低),棧中的 str 變量指向 "ABCD加點東西" 的內存地址,完成一次拼接。spa

  • 這樣作就十分費內存,也就是浪費資源。

關於 StringBuffer 和 StringBuilder

StringBuffer 和 StringBuilder 都是可擴展的字符串類型。code

StringBuffer 和 StringBuilder 工做方式

  • 舉個例子:
StringBuilder sb = new StringBuilder("ABCD");
sb.append("加點東西");
// 或者如下
StringBuffer sb = new StringBuffer("ABCD");
sb.append("加點東西");

StringBuffer 和 StringBuilder 的內部數組 默認長度 = 初始化字符串長度 + 16。因此當 new StringBuilder("ABCD"); 執行完 new 以後,實際上在 sb 中的 capacity() 的返回值是 20。 這時候會在堆區建立一個 StringBuffer 或者 StringBuilder 對象,同時會到方法去的產量池中尋找是否有 "ABCD" 這個常量,而後 StringBuffer 或者 StringBuilder 對象指向常量池的 "ABCD" 這個常量。對象

當執行 sb.append("加點東西"); 這行代碼的時候,編譯器就會去常量池找是否有 "ABCD加點東西" 常量,若是沒有那麼就看 StringBuffer 或者 StringBuilder 對象 的長度能都裝載下 "加點東西" 該字符串(若是不夠那麼就增長到當前長度的 150%)。此時的內存地址是不變的。

  • 因此相對 String 的每次拼接都要在內存中從新分配一塊內存空間,StringBuffer 或者 StringBuilder 的效率天然而言要給 String 的拼接速度要快。

StringBuffer 和 StringBuilder 區別

  • 既然說 StringBuffer 和 StringBuilder 效率差很少,那麼爲啥還要兩個?其中有什麼區別呢?

StringBufferStringBuilder 的實現方法前多了一個 synchronized,也就是同步鎖,這樣會使 StringBuffer 在併發編程中更加安全,可靠。StringBuilder 在平常開發中是最多見,也是效率最高的。

小結

  • 拼接效率:
StringBuilder > StringBuffer > String
  • 推薦使用 StringBuilder
相關文章
相關標籤/搜索