剛開始學習Java時,做爲只會C語言的小白,就爲其中的字符串操做而感到震撼。相比之下,C語言在字節數組中保存一個結尾的\0去表示字符串,想實現字符串拼接,還須要調用strcpy庫函數或者本身手動去複製數組,很是麻煩,更別提其餘複雜操做,而Java經過String類讓字符串操做變得十分簡單和方便。除此以外,還有stringbuilder等這些類的輔助,那麼本文就從String,StringBuiler和StringBuffer的區別開始,去探討Java中的字符串操做。html
Java 提供了 String 類來建立和操做字符串。在源碼中能夠看到,String類內部的實現也是一個字節數組,這個數組是final類型的,所以String是不可變的對象,每次在對String類進行改變的時候都會生成一個新的string對象,而後將指針指向新的string對象。java
和 String 類不一樣的是,StringBuilder 類的對象可以被屢次的修改,而且不產生新的對象。這個特性的意義在於,若是咱們進行大量的字符串操做,使用String類就會產生很大的性能消耗,而StringBuilder就能夠避免這個問題。正則表達式
StringBuffer 和StringBuiler之間的最大不一樣在於 StringBuilder 的方法不是線程安全的。express
因爲 StringBuilder 相較於 StringBuffer 有速度優點,因此多數狀況下建議使用 StringBuilder 類。然而在應用程序要求線程安全的狀況下,則必須使用 StringBuffer 類。數組
操做類型 | 說明 | 是否可變 | 線程安全性 | 性能 |
---|---|---|---|---|
Java中的String | String 類中使用 final 關鍵字修飾字符數組來保存字符串 |
不可變 | 線程安全 | 低 |
Java中的StringBuffer | 字符串變量 | 可變 | 線程安全 | 通常 |
Java中的StringBuilder | 字符串變量 | 可變 | 線程不安全 | 通常 |
C/C++ 中的char* 操做 | char *是一個指針,能夠 指向一個字符串數組 |
可變 | 不可知 | 高 |
C/C++中的char數組 | 用一個字符數組來保存字符串 | 不可變 | 不可知 | 高 |
C/C++中的String封裝類 | string能夠被當作是以字符 爲元素的一種容器。 |
可變 | 併發讀操做 是線程安全的 |
較高 |
@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)); }
執行100000次 String 耗時:32s 執行100000次 StringBuilder 耗時:2ms 執行100000次 StringBuffer 耗時:4ms
能夠看到String類的性能遠低於StringBuiler和StringBuffer,而StringBuiler在本次測試中比Stringbuffer提升了50%的性能安全
@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()); } }
文本中包含郵政編碼: 440834 123456 135363 440833 123456 135363 文本中包含區號-座機號碼: 020-12345678 010-12345678 文本中包含手機號: 13536373839 13536373739
通過測試和比較,能夠看到Java中同爲字符串操做,但因爲背後實現的原理不一樣,造成的性能差別也是十分巨大,相比之下,C/C++中的字符串操做性能更高。String類的性能遠低於StringBuiler和StringBuffer,而StringBuiler比Stringbuffer的性能稍微高一點。對性能的探究,最終仍是要回到使用場景,能夠總結得出,若是不涉及字符串操做,那麼String類是首選,若是涉及的字符串操做沒有線程安全問題,那麼使用StringBuilder,若是涉及的字符串操做存在線程安全問題,那麼使用StringBuffer併發