String、StringBuilder、StringBuffer

测试拼接速度

@Test
public void testString() {
    long before = System.currentTimeMillis();
    String s = "";
    for (int i = 0; i < 100000; i++) {
        s += "a";
    }
    long after = System.currentTimeMillis();
    System.out.println("String cost: " + (after - before));
}

@Test
public void testStringBuilder() {
    long before = System.currentTimeMillis();
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 100000; i++) {
        sb.append("a");
    }
    long after = System.currentTimeMillis();
    System.out.println("StringBuilder cost: " + (after - before));
}

@Test
public void testStringBuffer() {
    long before = System.currentTimeMillis();
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < 100000; i++) {
        sb.append("a");
    }
    long after = System.currentTimeMillis();
    System.out.println("StringBuffer cost: " + (after - before));
}
  • 测试的结果:

        StringBuilder cost: 5
        StringBuffer cost: 9
        String cost: 14029
    
  • 在循环中,String 拼接字符串的速度远低于 StringBuilder 和 StringBuffer

利用 javap 查看字节码文件,寻找其中的差异

  • 命令行执行

    javap -c StringTest.class
  • 结果可以看出,String 拼接的时候也是通过 StringBuilder 的 append 方法进行拼接的

  • 产生差异的原因是,在每次循环中,String 拼接的时候都 new 了一个 StringBuilder

  • StringBuffer 是线程安全的,只比 StringBuilder 稍慢了一点

    public void testString();
    Code:
    0: ldc           #2                  // String
    2: astore_1
    3: iconst_0
    4: istore_2
    5: iload_2
    6: ldc           #11                 // int 100000
    8: if_icmpge     37
    11: new           #4                  // class java/lang/StringBuilder
    14: dup
    15: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
    18: aload_1
    19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    22: ldc           #9                  // String a
    24: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    27: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    30: astore_1
    31: iinc          2, 1
    34: goto          5
    37: return
    
    public void testStringBuilder();
    Code:
    0: new           #4                  // class java/lang/StringBuilder
    3: dup
    4: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
    7: astore_1
    8: iconst_0
    9: istore_2
    10: iload_2
    11: ldc           #11                 // int 100000
    13: if_icmpge     29
    16: aload_1
    17: ldc           #9                  // String a
    19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    22: pop
    23: iinc          2, 1
    26: goto          10
    29: return
    
    public void testStringBuffer();
    Code:
    0: new           #12                 // class java/lang/StringBuffer
    3: dup
    4: invokespecial #13                 // Method java/lang/StringBuffer."<init>":()V
    7: astore_1
    8: iconst_0
    9: istore_2
    10: iload_2
    11: ldc           #11                 // int 100000
    13: if_icmpge     29
    16: aload_1
    17: ldc           #9                  // String a
    19: invokevirtual #14                 // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
    22: pop
    23: iinc          2, 1
    26: goto          10
    29: return

若不是循环,String 和 StringBuilder 拼接的速度是差不多的

  • java 测试代码

    @Test
    public void string() {
        String s = "";
        String ss = "cc";
        s += "a" + "b" + ss;
    }
        
    @Test
    public void stringBuilder() {
        StringBuilder sb = new StringBuilder();
        String ss = "cc";
        sb.append("a").append("b").append(ss);
    }
  • 字节码

    public void string();
    Code:
    0: ldc           #2                  // String
    2: astore_1
    3: ldc           #3                  // String cc
    5: astore_2
    6: new           #4                  // class java/lang/StringBuilder
    9: dup
    10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
    13: aload_1
    14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    17: ldc           #7                  // String ab
    19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    22: aload_2
    23: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    26: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    29: astore_1
    30: return
    
    public void stringBuilder();
    Code:
    0: new           #4                  // class java/lang/StringBuilder
    3: dup
    4: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
    7: astore_1
    8: ldc           #3                  // String cc
    10: astore_2
    11: aload_1
    12: ldc           #9                  // String a
    14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    17: ldc           #10                 // String b
    19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    22: aload_2
    23: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    26: pop
    27: return
  • 原因是同样只 new 了一个 StringBuilder,使用的也是它的 append 方法


seal_de
46 声望3 粉丝