之前在阅读《阿里巴巴Java开发手册》时,发现有一条是关于循环体中字符串拼接的建议,具体内容如下:
那么我们首先来用例子来看看在循环体中用 + 或者用 StringBuilder 进行字符串拼接的效率如何吧(JDK版本为 jdk1.8.0_201)。
public class StringConcatDemo { public static void main(String[] args) { long s1 = System.currentTimeMillis(); new StringConcatDemo().addMethod(); System.out.println("使用 + 拼接:" + (System.currentTimeMillis() - s1)); s1 = System.currentTimeMillis(); new StringConcatDemo().stringBuilderMethod(); System.out.println("使用 StringBuilder 拼接:" + (System.currentTimeMillis() - s1)); } public String addMethod() { String result = ""; for (int i = 0; i < 100000; i++) { result += (i + "wupx"); } return result; } public String stringBuilderMethod() { StringBuilder result = new StringBuilder(); for (int i = 0; i < 100000; i++) { result.append(i).append("wupx"); } return result.toString(); } }
执行结果如下:
使用 + 拼接:29282 使用 StringBuilder 拼接:4
为什么这两种方法的时间会差这么多呢?接下来让我们一起进一步研究。
为什么 StringBuilder 比 + 快这么多?
从字节码层面来看下,为什么循环体中字符串拼接 StringBuilder 比 + 快这么多?
使用 javac StringConcatDemo.java 命令编译源文件,使用 javap -c StringConcatDemo 命令查看字节码文件的内容。
其中 addMethod() 方法的字节码如下:
public java.lang.String addMethod(); Code: 0: ldc #16 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: ldc #17 // int 100000 8: if_icmpge 41 11: new #7 // class java/lang/StringBuilder 14: dup 15: invokespecial #8 // Method java/lang/StringBuilder."<init>":()V 18: aload_1 19: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 22: iload_2 23: invokevirtual #18 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 26: ldc #19 // String wupx 28: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 31: invokevirtual #12 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 34: astore_1 35: iinc 2, 1 38: goto 5 41: aload_1 42: areturn
可以看出,第 8 行到第 38 行构成了一个循环体:在第 8 行的时候做条件判断,如