1. 程式人生 > >Java 字串拼接效率比較

Java 字串拼接效率比較

1 字串拼接的三種方法

① 加號
② concat方法
③ StringBuilder(或StringBuffer)的append方法

2 程式例子

package com.jtzen9;
public class Main {
    public static void main(String[] args) {
        String str = "a";
        long time = System.currentTimeMillis();
        for (int i = 0; i < 50000; i++) {
            str += "c"
; } System.out.println("加號所花費的時間:"); System.out.println(System.currentTimeMillis()-time); String str2 = "a"; time = System.currentTimeMillis(); for (int i = 0; i < 50000; i++) { str2.concat("c"); } System.out.println("cancat方法所花費的時間:"
); System.out.println(System.currentTimeMillis()-time); time = System.currentTimeMillis(); StringBuilder stringBuilder = new StringBuilder("a"); for (int i = 0; i < 50000; i++) { stringBuilder.append("c"); } String str3 = stringBuilder.toString(); System.out.println("StringBuilder的append方法:"
); System.out.println(System.currentTimeMillis()-time); } }

程式輸出:
這裡寫圖片描述

3 append方法最快、concat次之、加號最慢

3.1 “+”方法

雖然編譯器對字串的加號做了優化,它會使用StringBuilder的append方法進行追加,而它最終通過toString方法轉換成String字串,上例中“+”拼接的程式碼即如下:

str = new StringBuilder(str).append("JTZen9").toString();

它與純粹地使用StringBuilder的append方法是不同的:
① 每趟迴圈都會建立一個StringBuilder物件
② 每次執行完畢都會呼叫toString方法將其轉換為字串
所以,就耗費了更多的時間。

3.2 concat方法

concat原始碼:

 public String concat(String str) {
        // 追加的字串長度為0
        int otherLen = str.length();
        // 如果追加的字串長度為0,則返回原字串本身
        if (otherLen == 0) {
            return this;
        }
        // 獲取原字串的字元陣列的長度
        int len = value.length;
        // 將原字串的字元陣列放到buf陣列中
        char buf[] = Arrays.copyOf(value, len + otherLen);
        // 追加的字串轉化成字元陣列,新增到buf中
        str.getChars(buf, len);
        // 產生一個新的字串
        return new String(buf, true);
    }

整體是一個數組的拷貝,雖然在記憶體中是處理都是原子性操作,速度非常快,但是,最後的return語句建立一個新String物件,也就是每次concat操作都會建立一個新的String物件,這也是限制concat方法速度的原因。

3.3 append方法

append原始碼:

public AbstractStringBuilder append(String str) {
        // 如果是null值,則把null作為字串處理
        if (str == null)
            return appendNull();
        int len = str.length();
        // 追加後的字元陣列長度是否超過當前值
        ensureCapacityInternal(count + len);
        // 字串複製到目標陣列
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
   private AbstractStringBuilder appendNull() {
        int c = count;
        ensureCapacityInternal(c + 4);
        final char[] value = this.value;
        value[c++] = 'n';
        value[c++] = 'u';
        value[c++] = 'l';
        value[c++] = 'l';
        count = c;
        return this;
    }
    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0)
            expandCapacity(minimumCapacity);  // 加長,並作陣列拷貝
    }

整個append方法都在做字元陣列的處理,加長,拷貝等,這些都是基本的資料處理,整個方法內並沒有生成物件。只是最後toString返回一個物件而已。

4 題外

(1)

String str = "My name is ";
str = str + "JTZen9";

相當於 str = new StringBuilder(str).append(“JTZen9”).toString();
也就是說,該str = str + “JTZen9”;語句執行完之後,總共有三個物件。

(2)

String str = "My name is " + "JTZen9";

JVM會直接把str作為一個物件,即 “My name is JTZen9”

5 使用場景

(1)大多數情況,我們使用“+”,符合編碼習慣和我們的閱讀
(2)當在頻繁進行字串的運算(如拼接、替換、刪除等),或者在系統性能臨界的時候,我們可以考慮使用concat或append方法