聲明:本人菜鳥,大牛請無視。
公司的某些大牛教導我們,Java中字符串拼接的話要用StringBuilder或者StringBuffer.不要用"+",會有性能問題。但我看Android的源碼,Google的工程師遍地都是"+".困惑了。So,驗證。
1 package com.vbo.javatest; 2 3 public class StringAppendTest { 4 private int mInteger = 1; 5 private static final int INTEGER = 1; 6 7 public static void main(String[] args) { 8 new StringAppendTest().stringAppendWithPlusSign(); 9 new StringAppendTest().stringAppendWithStringBuffer(); 10 new StringAppendTest().stringAppendWithStringBuilder(); 11 } 12 13 private void stringAppendWithPlusSign() { 14 String result1 = "1" + "1"; 15 String result2 = "1" + INTEGER; 16 String result3 = "1" + mInteger; 17 System.out.println(result1); 18 System.out.println(result2); 19 System.out.println(result3); 20 } 21 22 private void stringAppendWithStringBuffer() { 23 StringBuffer result = new StringBuffer(); 24 result.append("1"); 25 result.append(INTEGER); 26 result.append(mInteger); 27 System.out.println(result.toString()); 28 } 29 30 private void stringAppendWithStringBuilder() { 31 StringBuilder result = new StringBuilder(); 32 result.append("1"); 33 result.append(INTEGER); 34 result.append(mInteger); 35 System.out.println(result.toString()); 36 } 37 }
編譯再反編譯后的結果:
1 package com.vbo.javatest; 2 3 import java.io.PrintStream; 4 5 public class StringAppendTest 6 { 7 8 public StringAppendTest() 9 { 10 // 0 0:aload_0 11 // 1 1:invokespecial #13 <Method void Object()> 12 mInteger = 1; 13 // 2 4:aload_0 14 // 3 5:iconst_1 15 // 4 6:putfield #15 <Field int com.vbo.javatest.StringAppendTest.mInteger> 16 // 5 9:return 17 } 18 19 public static void main(java.lang.String args[]) 20 { 21 (new StringAppendTest()).stringAppendWithPlusSign(); 22 // 0 0:new #1 <Class com.vbo.javatest.StringAppendTest> 23 // 1 3:dup 24 // 2 4:invokespecial #23 <Method void StringAppendTest()> 25 // 3 7:invokespecial #24 <Method void com.vbo.javatest.StringAppendTest.stringAppendWithPlusSign()> 26 (new StringAppendTest()).stringAppendWithStringBuffer(); 27 // 4 10:new #1 <Class com.vbo.javatest.StringAppendTest> 28 // 5 13:dup 29 // 6 14:invokespecial #23 <Method void StringAppendTest()> 30 // 7 17:invokespecial #27 <Method void com.vbo.javatest.StringAppendTest.stringAppendWithStringBuffer()> 31 (new StringAppendTest()).stringAppendWithStringBuilder(); 32 // 8 20:new #1 <Class com.vbo.javatest.StringAppendTest> 33 // 9 23:dup 34 // 10 24:invokespecial #23 <Method void StringAppendTest()> 35 // 11 27:invokespecial #30 <Method void com.vbo.javatest.StringAppendTest.stringAppendWithStringBuilder()> 36 // 12 30:return 37 } 38 39 private void stringAppendWithPlusSign() 40 { 41 java.lang.String result1 = "11"; 42 // 0 0:ldc1 #35 <String "11"> 43 // 1 2:astore_1 44 java.lang.String result2 = "11"; 45 // 2 3:ldc1 #35 <String "11"> 46 // 3 5:astore_2 47 java.lang.String result3 = (new StringBuilder("1")).append(mInteger).toString(); 48 // 4 6:new #37 <Class java.lang.StringBuilder> 49 // 5 9:dup 50 // 6 10:ldc1 #39 <String "1"> 51 // 7 12:invokespecial #41 <Method void StringBuilder(java.lang.String)> 52 // 8 15:aload_0 53 // 9 16:getfield #15 <Field int com.vbo.javatest.StringAppendTest.mInteger> 54 // 10 19:invokevirtual #44 <Method java.lang.StringBuilder java.lang.StringBuilder.append(int)> 55 // 11 22:invokevirtual #48 <Method java.lang.String java.lang.StringBuilder.toString()> 56 // 12 25:astore_3 57 java.lang.System.out.println(result1); 58 // 13 26:getstatic #52 <Field java.io.PrintStream java.lang.System.out> 59 // 14 29:aload_1 60 // 15 30:invokevirtual #58 <Method void java.io.PrintStream.println(java.lang.String)> 61 java.lang.System.out.println(result2); 62 // 16 33:getstatic #52 <Field java.io.PrintStream java.lang.System.out> 63 // 17 36:aload_2 64 // 18 37:invokevirtual #58 <Method void java.io.PrintStream.println(java.lang.String)> 65 java.lang.System.out.println(result3); 66 // 19 40:getstatic #52 <Field java.io.PrintStream java.lang.System.out> 67 // 20 43:aload_3 68 // 21 44:invokevirtual #58 <Method void java.io.PrintStream.println(java.lang.String)> 69 // 22 47:return 70 } 71 72 private void stringAppendWithStringBuffer() 73 { 74 java.lang.StringBuffer result = new StringBuffer(); 75 // 0 0:new #67 <Class java.lang.StringBuffer> 76 // 1 3:dup 77 // 2 4:invokespecial #69 <Method void StringBuffer()> 78 // 3 7:astore_1 79 result.append("1"); 80 // 4 8:aload_1 81 // 5 9:ldc1 #39 <String "1"> 82 // 6 11:invokevirtual #70 <Method java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.String)> 83 // 7 14:pop 84 result.append(1); 85 // 8 15:aload_1 86 // 9 16:iconst_1 87 // 10 17:invokevirtual #73 <Method java.lang.StringBuffer java.lang.StringBuffer.append(int)> 88 // 11 20:pop 89 result.append(mInteger); 90 // 12 21:aload_1 91 // 13 22:aload_0 92 // 14 23:getfield #15 <Field int com.vbo.javatest.StringAppendTest.mInteger> 93 // 15 26:invokevirtual #73 <Method java.lang.StringBuffer java.lang.StringBuffer.append(int)> 94 // 16 29:pop 95 java.lang.System.out.println(result.toString()); 96 // 17 30:getstatic #52 <Field java.io.PrintStream java.lang.System.out> 97 // 18 33:aload_1 98 // 19 34:invokevirtual #76 <Method java.lang.String java.lang.StringBuffer.toString()> 99 // 20 37:invokevirtual #58 <Method void java.io.PrintStream.println(java.lang.String)> 100 // 21 40:return 101 } 102 103 private void stringAppendWithStringBuilder() 104 { 105 java.lang.StringBuilder result = new StringBuilder(); 106 // 0 0:new #37 <Class java.lang.StringBuilder> 107 // 1 3:dup 108 // 2 4:invokespecial #79 <Method void StringBuilder()> 109 // 3 7:astore_1 110 result.append("1"); 111 // 4 8:aload_1 112 // 5 9:ldc1 #39 <String "1"> 113 // 6 11:invokevirtual #80 <Method java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)> 114 // 7 14:pop 115 result.append(1); 116 // 8 15:aload_1 117 // 9 16:iconst_1 118 // 10 17:invokevirtual #44 <Method java.lang.StringBuilder java.lang.StringBuilder.append(int)> 119 // 11 20:pop 120 result.append(mInteger); 121 // 12 21:aload_1 122 // 13 22:aload_0 123 // 14 23:getfield #15 <Field int com.vbo.javatest.StringAppendTest.mInteger> 124 // 15 26:invokevirtual #44 <Method java.lang.StringBuilder java.lang.StringBuilder.append(int)> 125 // 16 29:pop 126 java.lang.System.out.println(result.toString()); 127 // 17 30:getstatic #52 <Field java.io.PrintStream java.lang.System.out> 128 // 18 33:aload_1 129 // 19 34:invokevirtual #48 <Method java.lang.String java.lang.StringBuilder.toString()> 130 // 20 37:invokevirtual #58 <Method void java.io.PrintStream.println(java.lang.String)> 131 // 21 40:return 132 } 133 134 private int mInteger; 135 private static final int INTEGER = 1; 136 }
當多個確定量(常量)字符串相加時(情況1),編譯器直接將它們編輯為相加后的字符串,這樣的情況下用“+”比StringBuilder運行時效率更高。
當相加的字符串中包含不確定量(變量)時(情況2),編譯器將“+”編譯為StringBuilder實現,這樣看起來兩者沒有本質區別,我們可以抽某些人的嘴巴了么?Too Simple, sometimes navie!
第三種情況:
1 String result = null; 2 for (int i = 0; i < 100; i++) { 3 result += mInteger; 4 } 5 6 StringBuilder result = new StringBuilder(); 7 for (int i = 0; i < 100; i++) { 8 result.append(mInteger); 9 }
編譯再反編譯后的結果:
1 private void stringAppendInLoop() 2 { 3 java.lang.String result = null; 4 // 0 0:aconst_null 5 // 1 1:astore_1 6 for(int i = 0; i < 100; i++) 7 //* 2 2:iconst_0 8 //* 3 3:istore_2 9 //* 4 4:goto 32 10 result = (new StringBuilder(java.lang.String.valueOf(result))).append(mInteger).toString(); 11 // 5 7:new #40 <Class java.lang.StringBuilder> 12 // 6 10:dup 13 // 7 11:aload_1 14 // 8 12:invokestatic #87 <Method java.lang.String java.lang.String.valueOf(java.lang.Object)> 15 // 9 15:invokespecial #44 <Method void StringBuilder(java.lang.String)> 16 // 10 18:aload_0 17 // 11 19:getfield #15 <Field int com.vbo.javatest.StringAppendTest.mInteger> 18 // 12 22:invokevirtual #47 <Method java.lang.StringBuilder java.lang.StringBuilder.append(int)> 19 // 13 25:invokevirtual #51 <Method java.lang.String java.lang.StringBuilder.toString()> 20 // 14 28:astore_1 21 22 // 15 29:iinc 2 1 23 // 16 32:iload_2 24 // 17 33:bipush 100 25 // 18 35:icmplt 7 26 java.lang.StringBuilder result1 = new StringBuilder(); 27 // 19 38:new #40 <Class java.lang.StringBuilder> 28 // 20 41:dup 29 // 21 42:invokespecial #82 <Method void StringBuilder()> 30 // 22 45:astore_2 31 for(int i = 0; i < 100; i++) 32 //* 23 46:iconst_0 33 //* 24 47:istore_3 34 //* 25 48:goto 63 35 result1.append(mInteger); 36 // 26 51:aload_2 37 // 27 52:aload_0 38 // 28 53:getfield #15 <Field int com.vbo.javatest.StringAppendTest.mInteger> 39 // 29 56:invokevirtual #47 <Method java.lang.StringBuilder java.lang.StringBuilder.append(int)> 40 // 30 59:pop 41 42 // 31 60:iinc 3 1 43 // 32 63:iload_3 44 // 33 64:bipush 100 45 // 34 66:icmplt 51 46 // 35 69:return 47 }
哦!!!"大牛"們說的是這個意思。用"+"導致new 了100個StringBuilder!
我向來不憚以最好的善意揣測“大牛”:他們沒有時間給出論據,只給出了論點,他們給出教誨時沒有時間給出前提條件。