经常看到一些论坛在谈java代码优化的时候讲到要将字符串连接操作”+”换成StringBuilder(或StringBuffer,后面为简单起见,只说StringBuilder)的append操作以提升性能,那么字符串连接使用StringBuilder#append来替代”+”真的会带来性能提升吗?
不忙回答,先看几个例子,代码如下:
| public class StringConcat { public static void main(String... args) { concat1(); concat2(); concat3(); } public static void concat1() { String s = "today is " + "a good day"; System.out.println(s); } public static void concat2() { int count = 2; String tmp = " on the desk"; String s2 = "there are " + count + " books " + tmp; System.out.println(s2); } public static void concat3() { String s3 = ""; for(int i=0; i<100; i++) { s3 = s3 + i; } System.out.println(s3); } } |
接下来分别分析下这三个操作字符串的方法,通过javap命令反编译.class文件:javap -c StringConcat ,获得字节码指令如下(只摘取concat1,concat2,concat3三个方法的):
| public static void concat1(); Code: 0: ldc #5; //String today is a good day 2: astore_0 3: getstatic #6; //Field java/lang/System.out:Ljava/io/PrintStream; 6: aload_0 7: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 10: return public static void concat2(); Code: 0: iconst_2 1: istore_0 2: ldc #8; //String on the desk 4: astore_1 5: new #9; //class java/lang/StringBuilder 8: dup 9: invokespecial #10; //Method java/lang/StringBuilder."
|
来分析下三个方法的字节码含义
在concat1中,是两个字面值(字符串常量)的连接,从concat1的字节码的第0条(0: ldc #5; //String today is a good day)可以看到,该方法直接从常量池加载”String today is a good day”,也就是说,String s = “today is ” + “a good day”;这条语句在编译后已经变成了一个字符串,等效于String s = “String today is a good day”,运行期间根本无需做连接操作了,所以对于字符串字面值的连接,使用StringBuilder是没有任何意义的。
在concat2中,是变量参与字符串的连接。从反编译的字节码中可以看出,编译期间已经转换成了StringBuilder的append操作,
| String s2 = "there are " + count + " books " + tmp; |
语句在编译之后已经等效于(即[5,30]之间的指令):
| String s2 = new StringBuilder().append("there are ").append(count).append(" books").append(tmp).toString(); |
由此可见,在这样的字符串连接代码里显式