Java字符串拼接的方法和性能比較

 字符串的拼接方法一般使用以下五種:

1、String 的加法 "+"

2、String 的concat() 方法

3、StringBuider 的append() 方法

4、StringBuffer 的append() 方法

5、lang3 包中的StringUtils.join() 方法

性能分析: 

方法1:String是final類,是不可變的,所以他一旦被實例化就無法被修改,所以String字符串的拼接,都是又生成了一個新的字符串,使用“+”進行拼接時,反編譯出的字節碼文件顯示先new一個StringBuilder 對象,然後進行append 操作,最後通過toString 方法返回String 對象,該方法適用於小數據量的操作,代碼方便簡潔,使用該方法更符合我們的編碼和閱讀習慣

String s1 = "";
s1 += "A";
// 反編譯後
s1 = new StringBuilder().append(s1).append("A").toString();

 方法2:concat() 方法實現的源代碼如下:

    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }

 通過源代碼可以看出,concat 方法是通過創建一個新的字符數組,然後將原字符串和拼接的字符串的值複製到這個字符數組上,並使用這個字符數組創建一個新的String 對象返回

方法3:StringBuilder 和 StringBuffer 類與String 類不同,它們並不是final 類,所以它們是可以修改的。它們都封裝了字符數組,append 方法會將字符直接拷貝到內部的字符數組中,如果字符數組的長度達到最大容量時,就會進行擴容,擴展的容量是當前容量的2倍再加2(可以近似的看作2的N次冪),並且會有未被使用的字符空間,所以,StringBuilder默認分配16個字符的空間,如果能明確字符的最大空間,建議使用如下方式,避免大量的內存空間浪費

new StringBuilder(int size) // 默認分配size個字符的空間

 方法4:StringBuffer 和StringBuilder 最大的區別是該方法使用了synchronized 進行聲明,是線程級別安全的方法,該類和StringBuilder 類都是繼承自AbstractStringBuilder 類,所以運行效率會比StringBuilder 慢一些

方法5:lang3 包的StringUtils.join() 方法的實現源碼如下所示,從以下的源代碼可以看出,該方法也是通過StringBuilder 來實實現的,(這裏不對該方法做性能比較,理解的朋友看下源代碼就知道性能如何了)

    public static <T> String join(T... elements) {
        return join((Object[])elements, (String)null);
    }

    public static String join(Object[] array, String separator) {
        return array == null ? null : join((Object[])array, separator, 0, array.length);
    }

    public static String join(Object[] array, String separator, int startIndex, int endIndex) {
        if (array == null) {
            return null;
        } else {
            if (separator == null) {
                separator = "";
            }

            int noOfItems = endIndex - startIndex;
            if (noOfItems <= 0) {
                return "";
            } else {
                StringBuilder buf = newStringBuilder(noOfItems);

                for(int i = startIndex; i < endIndex; ++i) {
                    if (i > startIndex) {
                        buf.append(separator);
                    }

                    if (array[i] != null) {
                        buf.append(array[i]);
                    }
                }

                return buf.toString();
            }
        }
    }

批量數據處理的比較:

批量數據的處理一般都會用到遍歷,對字符串連接應該使用StringBuilder/StringBuffer代替String的連接方式。因爲在使用String類拼接字符串時,Java虛擬機不僅要花時間生成對象,以後可能還需要花時間對這些對象進行垃圾回收和處理,因此,生成過多的對象將會給程序的性能帶來很大的影響。所以String 不能用來做批量數據的處理。

如下的Demo,數量級十萬,從運行時間很明顯看出性能如何:

public class Test {

    public static void main(String[] args) {
        String s1 = new String();
        String s2 = new String();
        StringBuilder sb1 = new StringBuilder();
        StringBuffer sb2 = new StringBuffer();
        int num = 100000;

        long t0 = System.currentTimeMillis();
        for (int i = 0; i < num; i++) {
            s1 += "A";
        }
        long t1 = System.currentTimeMillis();

        for (int i = 0; i < num; i++) {
            s2 = s2.concat("a");
        }
        long t2 = System.currentTimeMillis();

        for (int i = 0; i < num; i++) {
            sb1.append("A");
        }
        long t3 = System.currentTimeMillis();

        for (int i = 0; i < num; i++) {
            sb2.append("B");
        }
        long t4 = System.currentTimeMillis();
        System.out.println("String [+]\f"+ (t1 - t0)
                + "\nString [concat()]\f" + (t2 - t1)
                + "\nStringBuilder [append()]\f" + (t3 - t2)
                + "\nStringBuffer [append()]\f" + (t4 - t3));
    }
}

控制檯打印如下: 

String [+]    21948
String [concat()]    4179
StringBuilder [append()]     6
StringBuffer [append()]    11

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章