1. 程式人生 > >String,StringBuffer,StringBuilder三者的使用方法和區別

String,StringBuffer,StringBuilder三者的使用方法和區別

在java中,我們常常用到String型別來操作字串,但是用來操作字串變數的不僅僅只有String型別,還有StringBuilder和StringBuffer型別,儘管我們平時使用String型別比較多,但是在實際的開發中,這三種類型完全是三足鼎立的局面,根據不同的使用場景,我們要使用不同的型別,在很多情況下,使用StringBuilder和StringBuffer比使用String型別更快,還會有其它優點。

我們先來了解一下StringBuilder和StringBuffer的簡單用法,至於String的用法,我們就不再贅述了,後面拿他們三個作比較的時候我們會提到,因為StringBuffer和StringBuilder的方法基本上都一樣,所以我們共同介紹它們的方法

1.StringBuffer,StringBuilder的用法

toString()方法

將StringBuffer,StringBuilder物件轉換為String字串,常用在需要輸出的時候,因為StringBuffer和StringBuilder的物件不能直接輸出,例如:

StringBuffer s1 = new StringBuffer();
s1.toString();
append()方法

用於在字串的後面追加字串,當StringBuffer,StringBuilder中沒有字串的時候也可以append(),可以用來初始化,例如:

public static
void main(String[] args) { StringBuffer s1 = new StringBuffer().append("bbb"); s1.append("aaa"); System.out.println(s1.toString()); }

執行結果:
在這裡插入圖片描述

charaAt()方法

返回指定索引位置的字元,索引從0開始,例如:

public static void main(String[] args)
    {
        StringBuffer s1 = new StringBuffer
().append("bbb"); s1.append("aaa"); System.out.println(s1.toString()); System.out.println(s1.charAt(3)); }

結果:
在這裡插入圖片描述

deleteCharAt()方法

刪除指定索引位置的字元,例如:

public static void main(String[] args)
    {
        StringBuffer s1 = new StringBuffer().append("bbb");
        s1.append("aaa");
        System.out.println(s1.toString());
        s1.deleteCharAt(3);
        System.out.println(s1.toString());
    }

結果:
在這裡插入圖片描述

delete()方法

刪除從開始索引到結束索引的字串,例如:

public static void main(String[] args)
    {
        StringBuffer s1 = new StringBuffer().append("bbb");
        s1.append("aaa");
        System.out.println(s1.toString());
        s1.delete(2,4);
        System.out.println(s1.toString());

    }

結果:
在這裡插入圖片描述

insert()方法

在指定索引位置之前插入字串,例如:

public static void main(String[] args)
    {
        StringBuffer s1 = new StringBuffer().append("bbb");
        s1.append("aaa");
        System.out.println(s1.toString());
        s1.insert(2,"cc");
        System.out.println(s1.toString());
    }

結果:
在這裡插入圖片描述

indexOf()方法

返回指定字串的開始字元索引位置,還可以從某個字元索引位置開始向後匹配,沒有找到匹配的就會返回-1,例如:

public static void main(String[] args)
    {
        StringBuffer s1 = new StringBuffer().append("bbb");
        s1.append("aaa");
        System.out.println(s1.toString());
        System.out.println(s1.indexOf("ba"));
        System.out.println(s1.indexOf("ba",2));
        System.out.println(s1.indexOf("mn"));
    }

結果:
在這裡插入圖片描述

lastIndexOf()方法

和indexOf()的用法一樣,只不過是從後往前匹配,也支援從指定索引開始從後往前去匹配,例如:

 public static void main(String[] args)
    {
        StringBuffer s1 = new StringBuffer().append("bbb");
        s1.append("aaa");
        System.out.println(s1.toString());
        System.out.println(s1.lastIndexOf("b",5));
    }

結果:
在這裡插入圖片描述

reverse()方法

反轉字串,例如:

public static void main(String[] args)
    {
        StringBuffer s1 = new StringBuffer().append("bbb");
        s1.append("aaa");
        System.out.println(s1.toString());
        System.out.println(s1.reverse());
        System.out.println(s1.toString());
        System.out.println(s1.length());
    }

結果:
在這裡插入圖片描述

length()方法

返回字串的長度,例如:

public static void main(String[] args)
    {
        StringBuffer s1 = new StringBuffer().append("bbb");
        s1.append("aaa");
        System.out.println(s1.toString());
        System.out.println(s1.length());
    }

結果:
在這裡插入圖片描述

2.String、StringBuffer、StringBuilder的區別

重頭戲來了,前面的部分相信你即使沒有在StringBuffer/StringBuilder中用過,也在別的類中用過,那麼,這三個型別到底有什麼區別呢?怎麼選擇它們的應用場景呢?

首先,從效能、速度方面來說:

StringBuilder>StringBuffer>String

我們來做一個測試,我們分別使用String和StringBuilder建立變數,然後分別對它們進行加字串操作,由於時間太短,我們把這個過程使用for迴圈重複100000遍以放大差距:

public static void main(String[] args)
    {

        Long start1 = System.currentTimeMillis();//獲取開始時間
        for (int i=0;i<100000;i++)//重複10萬次進行String變數加操作
        {
            String str = "a";
            str+="b";
        }
        Long end1 = System.currentTimeMillis();//獲取結束時間
        System.out.println("String花費時間:"+(end1-start1));//打印出花費的時間

        Long start2 = System.currentTimeMillis();
        for (int i=0;i<100000;i++)//重複10萬次進行StringBuilder變數加操作
        {
            StringBuilder str2 = new StringBuilder("a");
            str2.append("b");
        }
        Long end2 = System.currentTimeMillis();
        System.out.println("StringBuilder花費時間:"+(end2-start2));

        Long start3 = System.currentTimeMillis();
        for (int i=0;i<100000;i++)//重複10萬次進行StringBuffer變數加操作
        {
            StringBuffer str2 = new StringBuffer("a");
            str2.append("b");
        }
        Long end3 = System.currentTimeMillis();
        System.out.println("StringBuffer花費時間:"+(end2-start2));
    }

實驗結果:
在這裡插入圖片描述
可以看到,放大了差距之後,String和StringBuilder、StringBuffer兩兄弟的差距還是蠻大的,那麼是什麼造成了這種差距呢?

在上面的程式中:

String str = "a";
str+="b";

這句話看似是對同一個String型別的str物件進行了加操作,但是實際上可不是同一個物件,事實上,我們先聲明瞭一個String型別的物件,值是"a",把str這個控制代碼指向了這個物件,然後,當我們把這個物件進行+=操作的時候,實際上是又建立了一個String物件,這個物件的值是"a"+“b"也就是"ab”,然後改變控制代碼str讓它指向了這個新的物件,原來的物件失去了引用,就被jvm垃圾回收了。而StringBuffer和StringBuilder可不是這樣,這兩兄弟是直接改變自己本身物件的值。
那麼,當我們進行了10萬次操作的時候,快慢差距自然就體現出來了。

這裡有人會問了,如果我把這句程式碼:

String str = "a";
str+="b";

改為:

String str = "a"+"b";

呢?

讓我們看一下執行效果:
在這裡插入圖片描述
哪怕是進行10萬次操作,String所花費的時間也是極少的,這是為什麼呢?

這是因為String和我們其它型別的變數不同,其它的非基本型別物件的值、資料都儲存在java的堆中,而String型別的變數的值是儲存jvm在方法區中的字串常量池中的。當我們執行:String str = “a”+“b”;這句話的時候,String會自動把這個物件的值看成"ab",然後在方法區中如果找到了值同樣為"ab"的,就會直接讓str控制代碼指向它,也就是說,我們的這句程式碼現在相當於:

String str = "ab";

這可比之前的String用法一遍遍反覆地去建立物件回收物件快多了,因此,即使重複10萬次依然還是很快。

從執行緒安全的角度去看

StringBuffer是執行緒安全的,而StringBuilder是執行緒不安全的,實驗的具體方法見此連結:https://blog.csdn.net/litterfrog/article/details/76862435

總結

String適用於少量的字串操作的情況
StringBuilder適用於單執行緒下在字元緩衝區進行大量操作的情況
StringBuffer適用多執行緒下在字元緩衝區進行大量操作的情況