上一節咱們講解了字符串的特性,除了字符串類外,還有兩個咱們也會常常用到的類,那就是StringBuffer和StringBuilder。由於字符串不可變,因此咱們每次對字符串的修改好比經過鏈接concat、trim等都會建立一個新的字符串對象,那麼咱們如何在不建立字符串垃圾(大量臨時的字符串)的 狀況下操做字符串呢?答案則是使用StringBuffer和StringBuilder,StringBuffer是舊類,可是在Java 5中新增了StringBuilder,而且在Enum,Generics等和Java中的Autoboxing方面進行了重大改進。安全
String和StringBuffer之間的主要區別是String是不可變的,而StringBuffer、StringBuilder可變,這也就意味着咱們能夠在建立StringBuffer對象時修改它而不建立任何新對象,這個可變屬性使StringBuffer成爲處理Java中的字符串的理想選擇,同時,這種可變性更加節省時間而且資源消耗更少。固然咱們能夠經過toString將StringBuffer轉換爲String。這兩個類幾乎相同,它們使用具備相同名稱的方法返回相同的結果,咱們看看StringBuffer和StringBuilder源碼中的Append方法便可知其區別:多線程
@Override public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; }
@Override public StringBuilder append(String str) { super.append(str); return this; }
線程安全:StringBuffer方法是同步的,這意味着一次只能有一個線程調用StringBuffer實例的方法。 另外一方面,StringBuilder方法不一樣步,所以多個線程能夠調用StringBuilder類中的方法而不會被阻塞。因此咱們得出結論,StringBuffer是一個線程安全的類,而StringBuilder則不是。若是咱們正在處理使用多線程的應用程序,那麼使用StringBuilder可能會有線程不安全風險。app
速度:StringBuffer實際上比StringBuilder慢兩到三倍。 這背後的緣由是StringBuffer同步,一次只容許一個對象在一個對象上執行,致使代碼執行速度慢得多。ide
StringBuffer和StringBuilder都有相同的方法(除了StringBuffer類中的synchronized方法聲明外),如下爲常見方法:性能
append()
insert()
replace()
delete()
reverse()
咱們經過以下示例來使用上述幾個經常使用方法:測試
public class Main { public static void main(String[] args) { StringBuffer sb = new StringBuffer("Buffer no 1"); System.out.println(sb); sb.append(" - and this is appended!"); System.out.println(sb); sb.insert(11, ", this is inserted"); System.out.println(sb); sb.replace(7, 9, "Number"); System.out.println(sb); sb.delete(7, 14); System.out.println(sb); sb.reverse(); System.out.println(sb); } }
接下來咱們來對String、StringBuffer、StringBuilder進行性能測試。 ui
String concatString = "concatString"; StringBuffer appendBuffer = new StringBuffer("appendBuffer"); StringBuilder appendBuilder = new StringBuilder("appendBuilder"); long timerStarted; timerStarted = System.currentTimeMillis(); for (int i = 0; i < 50000; i++) { concatString += " another string"; } System.out.println("Time needed for 50000 String concatenations: " + (System.currentTimeMillis() - timerStarted) + "ms"); timerStarted = System.currentTimeMillis(); for (int i = 0; i < 50000; i++) { appendBuffer.append(" another string"); } System.out.println("Time needed for 50000 StringBuffer appends: " + (System.currentTimeMillis() - timerStarted) + "ms"); timerStarted = System.currentTimeMillis(); for (int i = 0; i < 50000; i++) { appendBuilder.append(" another string"); } System.out.println("Time needed for 50000 StringBuilder appends: " + (System.currentTimeMillis() - timerStarted) + "ms");
如上打印輸出因Java虛擬機而異,從如上基準測試中咱們仍是能夠看出StringBuilder是字符串操做中最快的,次之StringBuffer,它比StringBuilder慢1倍多,最後是String這是字符串操做中最慢的。使用StringBuilder的時間比普通的String快一系列。那麼是否是說明咱們對字符串操做時,徹底摒棄使用字符串呢?固然不是,凡是沒絕對,好比對字符串只是簡單操做,直接使用字符串也沒有多大性能損耗。this
String:不可變(這意味着更多的內存消耗)而且在進行字符串操做時很是慢,可是線程安全。spa
StringBuffer:可變且內存有效,而且是線程安全的。 與更快的StringBuilders相比,它們的降低速度是速度。線程
StringBuilder:可變的且內存有效,它們是字符串操做中最快的,但不幸的是它不是線程安全的。
本節咱們比較了StringBuffer和StringBuilder的區別,算是作一個筆記,沒有什麼理解難點,若是咱們基於以上事實結論考慮,咱們始終會作出正確的選擇!