声明:本人菜鸟,大牛请无视。
某些大牛教导我们,Java中字符串拼接的话要用StringBuilder或者StringBuffer.不要用"+",会有性能问题。但我看Android的源码,Google的工程师遍地都是"+".困惑了。So,验证。
public class StringAppendTest { private int mInteger = 1; private static final int INTEGER = 1; public static void main(String[] args) { new StringAppendTest().stringAppendWithPlusSign(); new StringAppendTest().stringAppendWithStringBuffer(); new StringAppendTest().stringAppendWithStringBuilder(); } private void stringAppendWithPlusSign() { String result1 = "1" + "1"; String result2 = "1" + INTEGER; String result3 = "1" + mInteger; System.out.println(result1); System.out.println(result2); System.out.println(result3); } private void stringAppendWithStringBuffer() { StringBuffer result = new StringBuffer(); result.append("1"); result.append(INTEGER); result.append(mInteger); System.out.println(result.toString()); } private void stringAppendWithStringBuilder() { StringBuilder result = new StringBuilder(); result.append("1"); result.append(INTEGER); result.append(mInteger); System.out.println(result.toString()); } }
编译再反编译后的结果:
package com.vbo.javatest; import java.io.PrintStream; public class StringAppendTest { public StringAppendTest() { // 0 0:aload_0 // 1 1:invokespecial #13 <Method void Object()> mInteger = 1; // 2 4:aload_0 // 3 5:iconst_1 // 4 6:putfield #15 <Field int com.vbo.javatest.StringAppendTest.mInteger> // 5 9:return } public static void main(java.lang.String args[]) { (new StringAppendTest()).stringAppendWithPlusSign(); // 0 0:new #1 <Class com.vbo.javatest.StringAppendTest> // 1 3:dup // 2 4:invokespecial #23 <Method void StringAppendTest()> // 3 7:invokespecial #24 <Method void com.vbo.javatest.StringAppendTest.stringAppendWithPlusSign()> (new StringAppendTest()).stringAppendWithStringBuffer(); // 4 10:new #1 <Class com.vbo.javatest.StringAppendTest> // 5 13:dup // 6 14:invokespecial #23 <Method void StringAppendTest()> // 7 17:invokespecial #27 <Method void com.vbo.javatest.StringAppendTest.stringAppendWithStringBuffer()> (new StringAppendTest()).stringAppendWithStringBuilder(); // 8 20:new #1 <Class com.vbo.javatest.StringAppendTest> // 9 23:dup // 10 24:invokespecial #23 <Method void StringAppendTest()> // 11 27:invokespecial #30 <Method void com.vbo.javatest.StringAppendTest.stringAppendWithStringBuilder()> // 12 30:return } private void stringAppendWithPlusSign() { java.lang.String result1 = "11"; // 0 0:ldc1 #35 <String "11"> // 1 2:astore_1 java.lang.String result2 = "11"; // 2 3:ldc1 #35 <String "11"> // 3 5:astore_2 java.lang.String result3 = (new StringBuilder("1")).append(mInteger).toString(); // 4 6:new #37 <Class java.lang.StringBuilder> // 5 9:dup // 6 10:ldc1 #39 <String "1"> // 7 12:invokespecial #41 <Method void StringBuilder(java.lang.String)> // 8 15:aload_0 // 9 16:getfield #15 <Field int com.vbo.javatest.StringAppendTest.mInteger> // 10 19:invokevirtual #44 <Method java.lang.StringBuilder java.lang.StringBuilder.append(int)> // 11 22:invokevirtual #48 <Method java.lang.String java.lang.StringBuilder.toString()> // 12 25:astore_3 java.lang.System.out.println(result1); // 13 26:getstatic #52 <Field java.io.PrintStream java.lang.System.out> // 14 29:aload_1 // 15 30:invokevirtual #58 <Method void java.io.PrintStream.println(java.lang.String)> java.lang.System.out.println(result2); // 16 33:getstatic #52 <Field java.io.PrintStream java.lang.System.out> // 17 36:aload_2 // 18 37:invokevirtual #58 <Method void java.io.PrintStream.println(java.lang.String)> java.lang.System.out.println(result3); // 19 40:getstatic #52 <Field java.io.PrintStream java.lang.System.out> // 20 43:aload_3 // 21 44:invokevirtual #58 <Method void java.io.PrintStream.println(java.lang.String)> // 22 47:return } private void stringAppendWithStringBuffer() { java.lang.StringBuffer result = new StringBuffer(); // 0 0:new #67 <Class java.lang.StringBuffer> // 1 3:dup // 2 4:invokespecial #69 <Method void StringBuffer()> // 3 7:astore_1 result.append("1"); // 4 8:aload_1 // 5 9:ldc1 #39 <String "1"> // 6 11:invokevirtual #70 <Method java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.String)> // 7 14:pop result.append(1); // 8 15:aload_1 // 9 16:iconst_1 // 10 17:invokevirtual #73 <Method java.lang.StringBuffer java.lang.StringBuffer.append(int)> // 11 20:pop result.append(mInteger); // 12 21:aload_1 // 13 22:aload_0 // 14 23:getfield #15 <Field int com.vbo.javatest.StringAppendTest.mInteger> // 15 26:invokevirtual #73 <Method java.lang.StringBuffer java.lang.StringBuffer.append(int)> // 16 29:pop java.lang.System.out.println(result.toString()); // 17 30:getstatic #52 <Field java.io.PrintStream java.lang.System.out> // 18 33:aload_1 // 19 34:invokevirtual #76 <Method java.lang.String java.lang.StringBuffer.toString()> // 20 37:invokevirtual #58 <Method void java.io.PrintStream.println(java.lang.String)> // 21 40:return } private void stringAppendWithStringBuilder() { java.lang.StringBuilder result = new StringBuilder(); // 0 0:new #37 <Class java.lang.StringBuilder> // 1 3:dup // 2 4:invokespecial #79 <Method void StringBuilder()> // 3 7:astore_1 result.append("1"); // 4 8:aload_1 // 5 9:ldc1 #39 <String "1"> // 6 11:invokevirtual #80 <Method java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)> // 7 14:pop result.append(1); // 8 15:aload_1 // 9 16:iconst_1 // 10 17:invokevirtual #44 <Method java.lang.StringBuilder java.lang.StringBuilder.append(int)> // 11 20:pop result.append(mInteger); // 12 21:aload_1 // 13 22:aload_0 // 14 23:getfield #15 <Field int com.vbo.javatest.StringAppendTest.mInteger> // 15 26:invokevirtual #44 <Method java.lang.StringBuilder java.lang.StringBuilder.append(int)> // 16 29:pop java.lang.System.out.println(result.toString()); // 17 30:getstatic #52 <Field java.io.PrintStream java.lang.System.out> // 18 33:aload_1 // 19 34:invokevirtual #48 <Method java.lang.String java.lang.StringBuilder.toString()> // 20 37:invokevirtual #58 <Method void java.io.PrintStream.println(java.lang.String)> // 21 40:return } private int mInteger; private static final int INTEGER = 1; }
当多个确定量(常量)字符串相加时(情况1),编译器直接将它们编辑为相加后的字符串,这样的情况下用“+”比StringBuilder运行时效率更高。
当相加的字符串中包含不确定量(变量)时(情况2),编译器将“+”编译为StringBuilder实现,这样看起来两者没有本质区别? No!
第三种情况:
String result = null; for (int i = 0; i < 100; i++) { result += mInteger; } StringBuilder result = new StringBuilder(); for (int i = 0; i < 100; i++) { result.append(mInteger); }
编译再反编译后的结果:
private void stringAppendInLoop() { java.lang.String result = null; // 0 0:aconst_null // 1 1:astore_1 for(int i = 0; i < 100; i++) //* 2 2:iconst_0 //* 3 3:istore_2 //* 4 4:goto 32 result = (new StringBuilder(java.lang.String.valueOf(result))).append(mInteger).toString(); // 5 7:new #40 <Class java.lang.StringBuilder> // 6 10:dup // 7 11:aload_1 // 8 12:invokestatic #87 <Method java.lang.String java.lang.String.valueOf(java.lang.Object)> // 9 15:invokespecial #44 <Method void StringBuilder(java.lang.String)> // 10 18:aload_0 // 11 19:getfield #15 <Field int com.vbo.javatest.StringAppendTest.mInteger> // 12 22:invokevirtual #47 <Method java.lang.StringBuilder java.lang.StringBuilder.append(int)> // 13 25:invokevirtual #51 <Method java.lang.String java.lang.StringBuilder.toString()> // 14 28:astore_1 // 15 29:iinc 2 1 // 16 32:iload_2 // 17 33:bipush 100 // 18 35:icmplt 7 java.lang.StringBuilder result1 = new StringBuilder(); // 19 38:new #40 <Class java.lang.StringBuilder> // 20 41:dup // 21 42:invokespecial #82 <Method void StringBuilder()> // 22 45:astore_2 for(int i = 0; i < 100; i++) //* 23 46:iconst_0 //* 24 47:istore_3 //* 25 48:goto 63 result1.append(mInteger); // 26 51:aload_2 // 27 52:aload_0 // 28 53:getfield #15 <Field int com.vbo.javatest.StringAppendTest.mInteger> // 29 56:invokevirtual #47 <Method java.lang.StringBuilder java.lang.StringBuilder.append(int)> // 30 59:pop // 31 60:iinc 3 1 // 32 63:iload_3 // 33 64:bipush 100 // 34 66:icmplt 51 // 35 69:return }
用"+"导致new 了100个StringBuilder!
所以给出论点的同时需要给出论据,选择处理方式时需要考虑前提条件(不同场景)