什么时候引入Javac StringBuilder/StringBuffer优化?

Nic*_*s C 27 java stringbuilder javac stringbuffer jdk1.4

我知道Javac编译器能够+使用StringBuilder/ 来转换字符串连接StringBuffer,并且我很想知道从哪个版本引入了这个更改?

我正在使用此示例代码:

public class Main {
  public static void main(String[] args) {
      String a = args[0];
      String s = "a";
      s = s + a;
      s = s + "b";
      s = s + "c";
      s = s + "d";
      s = s + "e";
      System.out.println(s);
  }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,我已经试过javac 1.8.0_121,javac 1.6.0_20,javac 1.5.0_22和java 1.4.2_19.

这里是字节码我看到使用的样本javap -c来自1.4.2_19:

6:  astore_2
7:  new #3; //class StringBuffer
10: dup
11: invokespecial   #4; //Method java/lang/StringBuffer."<init>":()V
14: aload_2
15: invokevirtual   #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
18: aload_1
19: invokevirtual   #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
22: invokevirtual   #6; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
Run Code Online (Sandbox Code Playgroud)

所有4个版本似乎都在使用StringBuilder/StringBuffer优化,所以我很想知道从哪个Javac版本开始引入这个更改?

man*_*uti 31

这是来自版本1的语言规范的引用:

实现可以选择在一个步骤中执行转换和连接,以避免创建然后丢弃中间String对象.为了提高重复字符串连接的性能,Java编译器可以使用StringBuffer类(第20.13节)或类似技术来减少String通过表达式求值创建的中间对象的数量.

返回的时候,他们不得不StringBuffer代替StringBuilder.

也是StringBufferJDK1.0.2 的引用:

此类是字符的可增长缓冲区.它主要用于创建字符串.编译器使用它来实现"+"运算符.

  • @Aaron StringBuilder通常应该在构造复杂字符串时使用,例如在循环中(请参阅http://stackoverflow.com/questions/1532461/stringbuilder-vs-string-concatenation-in-tostring-in-java). (11认同)
  • 很好找,但现在我不得不鄙视我以前的老师教我使用`StringBuffer` /`Builder`的无用冗长的语法;-(我会试着找到一些安慰,相信它可能没有在早期版本的OpenJDK,请没有人破坏这个:p (2认同)

luk*_*keg 11

我查阅了Java语言规范,第一版(从1996年开始).不容易找到,但在这里.串联优化的过程即使在那时:

实现可以选择在一个步骤中执行转换和连接,以避免创建然后丢弃中间String对象.为了提高重复字符串连接的性能,Java编译器可以使用StringBuffer类(第20.13节)或类似技术来减少通过表达式求值创建的中间String对象的数量.

该规范涉及到StringBuffer当时,但StringBuilder(当前JLS措辞所指的)可能被认为表现更好,因为其方法不同步.

然而,这并不意味着人们应该始终如一地依赖优化.例如,循环中的字符串连接不会得到优化.


Shu*_*sia 5

JLS已经在一些答案中给出了.我只是想说明自1.0以来StringBuffer(https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html)在那里

StringBuilder(https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html)来自1.5版本.请参阅since:各自的javadoc部分.


Eug*_*ene 5

这并没有回答这个问题,但我只想补充一点,即在jdk-9中这StringBuilder::append是允许的策略之一,但不是默认策略.

private enum Strategy {
   /**
    * Bytecode generator, calling into {@link java.lang.StringBuilder}.
    */
    BC_SB,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but trying to estimate the required storage.
     */
    BC_SB_SIZED,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but computing the required storage exactly.
     */
     BC_SB_SIZED_EXACT,

   /**
    * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
    * This strategy also tries to estimate the required storage.
    */
    MH_SB_SIZED,

    /**
     * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
     * This strategy also estimate the required storage exactly.
     */
    MH_SB_SIZED_EXACT,

    /**
     * MethodHandle-based generator, that constructs its own byte[] array from
     * the arguments. It computes the required storage exactly.
     */
     MH_INLINE_SIZED_EXACT
}
Run Code Online (Sandbox Code Playgroud)

它实际上是invokedynamic字符串连接的字节码,因此它的实现现在是JRE特定的,而不是编译器.默认策略btw是:MH_INLINE_SIZED_EXACT