Java中的字元串操作(比較String,StringBuiler和StringBuffer)
一、前言
剛開始學習Java時,作為只會C語言的小白,就為其中的字元串操作而感到震撼。相比之下,C語言在位元組數組中保存一個結尾的\0去表示字元串,想實現字元串拼接,還需要調用strcpy庫函數或者自己手動去複製數組,非常麻煩,更別提其他複雜操作,而Java通過String類讓字元串操作變得十分簡單和方便。除此之外,還有stringbuilder等這些類的輔助,那麼本文就從String,StringBuiler和StringBuffer的區別開始,去探討Java中的字元串操作。
二、String,StringBuiler和StringBuffer
2.1 String類
Java 提供了 String 類來創建和操作字元串。在源碼中可以看到,String類內部的實現也是一個位元組數組,這個數組是final類型的,因此String是不可變的對象,每次在對String類進行改變的時候都會生成一個新的string對象,然後將指針指向新的string對象。
2.2 StringBuiler 類
和 String 類不同的是,StringBuilder 類的對象能夠被多次的修改,並且不產生新的對象。這個特性的意義在於,如果我們進行大量的字元串操作,使用String類就會產生很大的性能消耗,而StringBuilder就可以避免這個問題。
2.3 StringBuffer 類
StringBuffer 和StringBuiler之間的最大不同在於 StringBuilder 的方法不是執行緒安全的。
由於 StringBuilder 相較於 StringBuffer 有速度優勢,所以多數情況下建議使用 StringBuilder 類。然而在應用程式要求執行緒安全的情況下,則必須使用 StringBuffer 類。
2.4 String,StringBuiler和StringBuffer的比較(對比C/C++)
操作類型 | 說明 | 是否可變 | 執行緒安全性 | 性能 |
---|---|---|---|---|
Java中的String | String 類中使用 final 關鍵字修飾字元數組來保存字元串 |
不可變 | 執行緒安全 | 低 |
Java中的StringBuffer | 字元串變數 | 可變 | 執行緒安全 | 一般 |
Java中的StringBuilder | 字元串變數 | 可變 | 執行緒不安全 | 一般 |
C/C++ 中的char* 操作 | char *是一個指針,可以 指向一個字元串數組 |
可變 | 不可知 | 高 |
C/C++中的char數組 | 用一個字元數組來保存字元串 | 不可變 | 不可知 | 高 |
C/C++中的String封裝類 | string可以被看成是以字元 為元素的一種容器。 |
可變 | 並發讀操作 是執行緒安全的 |
較高 |
三、各種字元串操作的效率測試
3.1 測試程式碼
@Test
public void test() {
int count = 100000;
long startTime = System.currentTimeMillis();
String str = "";
for(int i = 0; i< count; i++){
str += i;
}
System.out.println("執行"+count+"次 String 耗時:"+ getRunTime(startTime));
startTime = System.currentTimeMillis();
StringBuilder stringBuilder = new StringBuilder("");
for (int i = 0; i < count; i++) {
stringBuilder.append(i);
}
System.out.println("執行"+count+"次 StringBuilder 耗時:"+ getRunTime(startTime));
startTime = System.currentTimeMillis();
StringBuffer stringBuffer = new StringBuffer("");
for (int i = 0; i < count; i++) {
stringBuffer.append(i);
}
System.out.println("執行"+count+"次 StringBuffer 耗時:"+ getRunTime(startTime));
}
3.2 測試結果
執行100000次 String 耗時:32s
執行100000次 StringBuilder 耗時:2ms
執行100000次 StringBuffer 耗時:4ms
3.3 小結
可以看到String類的性能遠低於StringBuiler和StringBuffer,而StringBuiler在本次測試中比Stringbuffer提高了50%的性能
四、Java字元串和正則表達式
4.1 測試程式碼
@Test
public void test0(){
//郵政編碼
String postCode = "[1-9]\\d{5}";
//區號-座機號碼
String areaCode = "\\d{3}-\\d{8}|\\d{4}-\\d{7}";
//手機號碼
String phone = "(?:13\\d|15\\d|18\\d)\\d{5}(\\d{3}|\\*{3})";
String text = "郵政編碼:440834"+
"區號-座機號碼: 020-12345678"+
"手機號:13536373839"+
"郵政編碼:440833"+
"區號-座機號碼: 010-12345678"+
"手機號:13536373739";
Pattern p = Pattern.compile(postCode);
Matcher m = p.matcher(text);
System.out.println("文本中包含郵政編碼:");
while (m.find()){
System.out.println(m.group());
}
p = Pattern.compile(areaCode);
m= p.matcher(text);
System.out.println("文本中包含區號-座機號碼:");
while (m.find()){
System.out.println(m.group());
}
p = Pattern.compile(phone);
m= p.matcher(text);
System.out.println("文本中包含手機號:");
while (m.find()){
System.out.println(m.group());
}
}
4.2 測試結果
文本中包含郵政編碼:
440834
123456
135363
440833
123456
135363
文本中包含區號-座機號碼:
020-12345678
010-12345678
文本中包含手機號:
13536373839
13536373739
五、總結
經過測試和比較,可以看到Java中同為字元串操作,但由於背後實現的原理不同,形成的性能差異也是十分巨大,相比之下,C/C++中的字元串操作性能更高。String類的性能遠低於StringBuiler和StringBuffer,而StringBuiler比Stringbuffer的性能稍微高一點。對性能的探究,最終還是要回到使用場景,可以總結得出,如果不涉及字元串操作,那麼String類是首選,如果涉及的字元串操作沒有執行緒安全問題,那麼使用StringBuilder,如果涉及的字元串操作存在執行緒安全問題,那麼使用StringBuffer
六、參考資料
- 探秘Java中的String、StringBuilder以及StringBuffer
- java中String StringBuilder StringBuffer比較和效率(性能)測試 – 行者老夫 – 部落格園
- Java 正則表達式