String串联是否经过优化以使用现有的StringBuilders?

Ant*_*nev 22 java performance java-8 java-9

我有以下代码:

StringBuilder str = new StringBuilder("foo");
for(Field f : fields){
    str.append("|" + f);
}
str.append("|" + bar);
String result = str.toString();
Run Code Online (Sandbox Code Playgroud)

我知道编译器会优化字符串连接"|" + f并用StringBuilder替换它.但是,是否会创建一个新的StringBuilder,或者现有的str将在Java 8中使用?Java 9怎么样?

Eug*_*ene 23

默认情况下,java-9中没有StringBuilder字符串连接 - 它是运行时决定它是如何通过invokedynamic.而默认的策略是不是一个StringBuilder::append一个.

您还可以在这里阅读更多内容.

在java-8下,将创建一个新的(很容易invokespecial // Method java/lang/StringBuilder."<init>":()V在解编译的字节码中发现两次出现).

另外,你有一个建议append.append...; 只是注意到这要好得多sb.append ... sb.append,就是为什么.

  • @Shirkam阅读了我的其他编辑,我觉得它也很酷. (2认同)
  • @Shirkam:与[lambda expressions](https://docs.oracle.com/javase/8/docs/api/?java/lang/invoke/LambdaMetafactory.html)一样,API中有明显的影响,是[今天已经记录](http://download.java.net/java/jdk9/docs/api/?java/lang/invoke/StringConcatFactory.html)... (2认同)

mer*_*ike 8

由于字符串连接优化由Java编译器执行,您可以通过反编译字节代码来查看它的作用:

$ cat Test.java
interface Field {}

public class Test {

    static String toString(Field[] fields, Object bar) {
        StringBuilder str = new StringBuilder("foo");
        for(Field f : fields){
            str.append("|" + f);
        }
        str.append("|" + bar);
        return str.toString();
    }
}
$ javac Test.java
$ javap -c Test.class
Compiled from "Test.java"
public class stackoverflow.Test {
  public stackoverflow.Test();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  static java.lang.String toString(stackoverflow.Field[], java.lang.Object);
    Code:
       0: new           #16                 // class java/lang/StringBuilder
       3: dup
       4: ldc           #18                 // String foo
       6: invokespecial #20                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
       9: astore_2
      10: aload_0
      11: dup
      12: astore        6
      14: arraylength
      15: istore        5
      17: iconst_0
      18: istore        4
      20: goto          53
      23: aload         6
      25: iload         4
      27: aaload
      28: astore_3
      29: aload_2
      30: new           #16                 // class java/lang/StringBuilder
      33: dup
      34: ldc           #23                 // String |
      36: invokespecial #20                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      39: aload_3
      40: invokevirtual #25                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      43: invokevirtual #29                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      46: invokevirtual #32                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      49: pop
      50: iinc          4, 1
      53: iload         4
      55: iload         5
      57: if_icmplt     23
      60: aload_2
      61: new           #16                 // class java/lang/StringBuilder
      64: dup
      65: ldc           #23                 // String |
      67: invokespecial #20                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      70: aload_1
      71: invokevirtual #25                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      74: invokevirtual #29                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      77: invokevirtual #32                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      80: pop
      81: aload_2
      82: invokevirtual #29                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      85: areturn
}
Run Code Online (Sandbox Code Playgroud)

如您所见,代码Method java/lang/StringBuilder."<init>":在3个位置调用StringBuilder构造函数(),因此将在每次迭代中创建新的StringBuilders(除非实时编译器执行花式优化).

这不太可能是一个重大的性能问题,但在不太可能的情况下,你可以通过重写来轻松解决这个问题

str.append("|").append(f);
Run Code Online (Sandbox Code Playgroud)