String:String / StringBuffer / StringBuilder 三者的功能區別

String 做爲最基礎的引用數據類型,平常的開發中被大量的使用。基於不可變的特性,一旦被過分地使用,堆內存就會負荷不堪,甚至影響性能,爲此,Java 設計者特地爲 String 在方法區中開闢了字符串常量池,以減小 String 的實例建立,然而,在面對大數量的狀況下,字符串常量池也未必能解決問題,所以,AbstractStringBuilder 應運而生,就是爲了解決 String頻繁建立而引起的內存性能降低的問題。java

帶着兩個問題,去看看String / StringBuffer / StringBuilder 的區別程序員

  • String vs AbstractStringBuilder編程

  • StringBuffer vs StringBuilder安全

  • String / StringBuffer / StringBuilder 的使用策略多線程


String vs AbstractStringBuilder

  • 擴容機制app

    • Stringide

      • 不可變性:從新建立一個對象模塊化

    String 底層代碼實現:性能

    • String 類被 final 修飾,該類不能被繼承測試

    • value[] 屬性 被final 修飾 ,引用不能修改

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];   //

    /** Cache the hash code for the string */
    private int hash; // Default to 0```
    
    //other codes

測試代碼:

String str = new String("a");
        str = str  + 「b」 ;

圖示:

圖片描述

  • AbstractStringBuilder

    • 可變性

    AbstractStringBuilder 底層代碼實現:

    • value[] 相對於 String ,沒有被final修飾

    • append("String") 返回時對象自己,不會建立新的對象

abstract class AbstractStringBuilder implements Appendable, CharSequence {
     /**
     * The value is used for character storage.
     */
    char[] value;

    /**
     * The count is the number of characters used.
     */
    int count;
    
    
    // other codes 
    
    
    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
    
    //other codes
}

測試代碼:

StringBuffer sb = new StringBuffer("a");
               sb.append("b");

圖示:
圖片描述

  • 性能比較

public class StringBufferWithStringBuilder {

    public void testString() {
        long start = System.currentTimeMillis();
        String str = null;
        for (int i = 0; i < 20000; i++) {
            str = str + i + ",";
        }
        System.out.println(System.currentTimeMillis() - start); 
    }

    public void testStringBuffer() {
        long start = System.currentTimeMillis();

        StringBuffer sbuf = new StringBuffer();
        for (int i = 0; i < 20000; i++) {
            sbuf.append(i + ",");
        }
        System.out.println(System.currentTimeMillis() - start);
    }

    public void testStringBulider() {
        long start = System.currentTimeMillis();

        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 20000; i++) {
            builder.append(i + ",");
        }
        System.out.println(System.currentTimeMillis() - start);
    }

    @Test
    public void test(){
        testString();
        testStringBuffer();
        testStringBulider();
    }
    
}

經過測試數據得知,在性能和效率上:StringBuilder>StringBuffer>String

緣由在於:

  • String 每執行一次 + 重載運算符,必須建立一個新的對象

  • StringBuilder 與 StringBuffer相比,少了同步鎖

StringBuffer vs StringBuilder

  • 線程安全

    • StringBuffer 是線程安全的

    • StringBuilder 是線程不安全

底層實現: StringBuffer 經過 synchronized 關鍵字的修飾,保證了資源不會被搶佔,從而確保了線程安全

/**
     * @since      1.5
     */
    @Override
    public synchronized void trimToSize() {
        super.trimToSize();
    }

    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @see        #length()
     */
    @Override
    public synchronized void setLength(int newLength) {
        toStringCache = null;
        super.setLength(newLength);
    }

String / StringBuffer / StringBuilder 的使用策略

  • 基本原則:若是要操做少許的數據,用String ;單線程操做大量數據,用StringBuilder ;多線程操做大量數據,用StringBuffer

  • 不要使用String類的"+"來進行頻繁的拼接,由於那樣的性能極差的,應該使用StringBuffer或StringBuilder類,這在Java的優化上是一條比較重要的原則

  • 爲了得到更好的性能,在構造 StringBuffer 或 StringBuilder 時應儘量指定它們的容量。固然,若是你操做的字符串長度(length)不超過 16 個字符就不用了,當不指定容量(capacity)時默認構造一個容量爲16的對象。不指定容量會顯著下降性能

  • StringBuilder通常使用在方法內部來完成相似"+"功能,由於是線程不安全的,因此用完之後能夠丟棄。StringBuffer主要用在全局變量中

  • 相同狀況下使用 StringBuilder 相比使用 StringBuffer 僅能得到 10%~15% 左右的性能提高,但卻要冒多線程不安全的風險。而在現實的模塊化編程中,負責某一模塊的程序員不必定能清晰地判斷該模塊是否會放入多線程的環境中運行,所以:除非肯定系統的瓶頸是在 StringBuffer 上,而且肯定你的模塊不會運行在多線程模式下,才能夠採用StringBuilder;不然仍是用StringBuffer

相關文章
相關標籤/搜索