Java 字串拼接四種方式的效能比較分析
一、簡單介紹
編寫程式碼過程中,使用"+"和"contact"比較普遍,但是它們都不能滿足大資料量的處理,一般情況下有一下四種方法處理字串拼接,如下:
1、 加號"+"
2、 String
的 contact()
方法
3、 StringBuffer
的 append()
方法
4、 StringBuilder
的 append()
方法
二、測試程式碼參考
StringTest
類
package com.jdk8.event.StringTest; public class StringTest { private static final int max = 100000; public static void testPlus() { System.out.println("************ plusTest() ************"); String str = ""; long start = System.currentTimeMillis(); for (int i = 0; i < max; i++) { str = str + "a"; } long end = System.currentTimeMillis(); long cost = end - start; System.out.println(" {str + \"a\"} cost=" + cost + " ms"); } public static void testConcat() { System.out.println("************ concatTest() ************"); String str = ""; long start = System.currentTimeMillis(); for (int i = 0; i < max; i++) { str = str.concat("a"); } long end = System.currentTimeMillis(); long cost = end - start; System.out.println(" {str.concat(\"a\")} cost=" + cost + " ms"); } public static void testStringBuffer() { System.out.println("************ StringBufferTest() ************"); long start = System.currentTimeMillis(); StringBuffer strBuffer = new StringBuffer(); for (int i = 0; i < max; i++) { strBuffer.append("a"); } strBuffer.toString(); long end = System.currentTimeMillis(); long cost = end - start; System.out.println(" {strBuffer.append(\"a\")} cost=" + cost + " ms"); } public static void testStringBuilder() { System.out.println("************ StringBuilderTest() ************"); long start = System.currentTimeMillis(); StringBuilder strBuilder = new StringBuilder(); for (int i = 0; i < max; i++) { strBuilder.append("a"); } strBuilder.toString(); long end = System.currentTimeMillis(); long cost = end - start; System.out.println(" {strBuilder.append(\"a\")} cost=" + cost + " ms"); } }
測試類:TestMain
package com.jdk8.event.StringTest; public class TestMain { public static void main(String[] args){ System.out.println("執行100次時"); StringTest.testPlus(); StringTest.testConcat(); StringTest.testStringBuffer(); StringTest.testStringBuilder(); } }
測試結果如下:
執行100次時 ************ plusTest() ************ {str + "a"} cost=0 ms ************ concatTest() ************ {str.concat("a")} cost=0 ms ************ StringBufferTest() ************ {strBuffer.append("a")} cost=0 ms ************ StringBuilderTest() ************ {strBuilder.append("a")} cost=0 ms
執行1000次時
************ concatTest() ************
{str.concat("a")} cost=1 ms
************ StringBufferTest() ************
{strBuffer.append("a")} cost=0 ms
************ StringBuilderTest() ************
{strBuilder.append("a")} cost=0 ms
執行10000次時
************ plusTest() ************
{str + "a"} cost=99 ms
************ concatTest() ************
Disconnected from the target VM, address: '127.0.0.1:63818', transport: 'socket'
{str.concat("a")} cost=17 ms
************ StringBufferTest() ************
{strBuffer.append("a")} cost=1 ms
************ StringBuilderTest() ************
{strBuilder.append("a")} cost=0 ms
執行100000次時
************ plusTest() ************
{str + "a"} cost=6176 ms
************ concatTest() ************
{str.concat("a")} cost=1267 ms
************ StringBufferTest() ************
{strBuffer.append("a")} cost=3 ms
************ StringBuilderTest() ************
Disconnected from the target VM, address: '127.0.0.1:63841', transport: 'socket'
{strBuilder.append("a")} cost=2 ms
執行300000次時
************ plusTest() ************
{str + "a"} cost=23554 ms
************ concatTest() ************
{str.concat("a")} cost=17667 ms
************ StringBufferTest() ************
{strBuffer.append("a")} cost=6 ms
************ StringBuilderTest() ************
{strBuilder.append("a")} cost=5 ms
執行500000次時
************ plusTest() ************
{str + "a"} cost=61421 ms
************ concatTest() ************
{str.concat("a")} cost=53173 ms
************ StringBufferTest() ************
{strBuffer.append("a")} cost=9 ms
************ StringBuilderTest() ************
{strBuilder.append("a")} cost=7 ms
1、 方法1 "+"號和方法2 contact()
方法適用於資料量比較小的情況下。為了操作程式碼風格和養成習慣,還是建議儘量不用
2、方法2 StringBuffer
的 append()
方法和StringBuilder
的 append()
方法 本質上是一樣的,均繼承自AbstractStringBuilder
抽象類,效率很高,資料量比較大的時候的推薦用法。區別是StringBuffer
是執行緒安全的,而StringBuilder
是執行緒不安全的。
三、原始碼分析
1、 String
的"+"方法,編譯器對其做了優化,使用StringBuilder
的append()
方法進行追加,但是每迴圈一次都會建立一個StringBuilder
物件,且都會呼叫toString()
方法轉換為子婦產,因此開銷很大。
注:執行一次String
的"+"方法,相當於str = new StringBuilder(str).append("x").toString()
;
2、呼叫String
的contact()
方法,其實就是一次陣列的拷貝,雖然在記憶體中的處理都是原子操作,速度很快,但是當返回時是要建立一個新的String物件的,這樣不僅限制了效率,更添加了空間的壓力,原始碼如下:
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
3、StringBuffer
和StringBuilder
的append()
方法均主要使用父類AbstractStringBuilder
的append()
方法。原始碼如下:
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;
}
即當陣列空間夠用的時候,只是在陣列後面新增字元或字串,並不建立新的物件,只是到最後通過toString()
方法來生成最終的字串,效率很快,也很節省空間,是推薦的用法。