相信很多人和我一样,在刚开始编写java程序时,只要出现字符串连接的地方直接一个“+”,觉得简单,方便,省事。
后来随着编码越来越多,阅读的书籍也越来越广,开始知道,在一些环境下使用StringBuilder(jdk1.5之前是StringBuffer,StringBuffer是线程安全的,但是在普通情况下使用反而会导致性能急剧下降)的效率会比高,相信大家查阅资料都可以知道,java编译器经过编译后,把我们使用的+自动转化为StringBuilder;
如图所示,我们根据字节码工具,可以清楚的知道了我们的方法被转换为使用StringBuilder,既然编译器已经帮我们做了,为什么我们还需要自己去使用StringBuilder呢;
private String getStr1() { String a = "1"; String b = "2"; String c = "3"; String d = "4"; String f = ""; f = a + b + c + d; return f; } private String getStr2() { String a = "1"; String b = "2"; String c = "3"; String d = "4"; String f = ""; b = a + b; c = b + c; f = c + d; return f; }
大家看看如上代码,这两个方法效果一样么?答案肯定是一致的,那这两个方法性能一致么?
我们同样来看看这两个方法的字节码:
private getStr1()Ljava/lang/String;
L0
LINENUMBER 20 L0
LDC "1"
ASTORE 1
L1
LINENUMBER 21 L1
LDC "2"
ASTORE 2
L2
LINENUMBER 22 L2
LDC "3"
ASTORE 3
L3
LINENUMBER 23 L3
LDC "4"
ASTORE 4
L4
LINENUMBER 24 L4
LDC ""
ASTORE 5
L5
LINENUMBER 25 L5
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 3
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 4
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 5
L6
LINENUMBER 26 L6
ALOAD 5
ARETURN
L7
LOCALVARIABLE this Lcom/hik/yuntest/StringTest; L0 L7 0
LOCALVARIABLE a Ljava/lang/String; L1 L7 1
LOCALVARIABLE b Ljava/lang/String; L2 L7 2
LOCALVARIABLE c Ljava/lang/String; L3 L7 3
LOCALVARIABLE d Ljava/lang/String; L4 L7 4
LOCALVARIABLE f Ljava/lang/String; L5 L7 5
MAXSTACK = 2
MAXLOCALS = 6
// access flags 0x2
private getStr2()Ljava/lang/String;
L0
LINENUMBER 30 L0
LDC "1"
ASTORE 1
L1
LINENUMBER 31 L1
LDC "2"
ASTORE 2
L2
LINENUMBER 32 L2
LDC "3"
ASTORE 3
L3
LINENUMBER 33 L3
LDC "4"
ASTORE 4
L4
LINENUMBER 34 L4
LDC ""
ASTORE 5
L5
LINENUMBER 35 L5
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 2
L6
LINENUMBER 36 L6
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 3
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 3
L7
LINENUMBER 37 L7
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 3
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 4
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 5
L8
LINENUMBER 38 L8
ALOAD 5
ARETURN
L9
LOCALVARIABLE this Lcom/hik/yuntest/StringTest; L0 L9 0
LOCALVARIABLE a Ljava/lang/String; L1 L9 1
LOCALVARIABLE b Ljava/lang/String; L2 L9 2
LOCALVARIABLE c Ljava/lang/String; L3 L9 3
LOCALVARIABLE d Ljava/lang/String; L4 L9 4
LOCALVARIABLE f Ljava/lang/String; L5 L9 5
MAXSTACK = 2
MAXLOCALS = 6
看到上面的字节码是不是晕了,放心我也看不懂,不过看看我标红的那几句话,同样的效果,同样使用+连接符,方法getStr1只new了一个StringBuilder,而getStr2却new了三个,说明getStr1与我们直接使用StringBuilder的方式是一模一样的,在同一个语句行使用+,它就会直接使用append将字符串追加进去,不产生新的对象,但是分行写,每段的“+”操作,都会产生一个新的对象,从而性能会损失掉,所以如果我们在循环里面拼接字符串,就不要使用“+”。实在是想使用“+”,尽量将语句放在一行解决,但是这样书法又不太美观,总之,一句话,在合适的地方使用“+”,如果你在乎你的性能