Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javac StringBuilder/StringBuffer优化是何时引入的?_Java_Javac_Stringbuilder_Stringbuffer_Jdk1.4 - Fatal编程技术网

Javac StringBuilder/StringBuffer优化是何时引入的?

Javac StringBuilder/StringBuffer优化是何时引入的?,java,javac,stringbuilder,stringbuffer,jdk1.4,Java,Javac,Stringbuilder,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";

我知道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);
  }
}
到目前为止,我已经尝试了
javac1.8.0\u121
javac1.6.0\u20
javac1.5.0\u22
java1.4.2\u19

下面是我使用
1.4.2_19
中的
javap-c
看到的字节码示例:

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;
6:astore_2
7:新#3//类字符串缓冲区
10:dup
11:特别是#4//方法java/lang/StringBuffer。“”:()V
14:aload_2
15:invokevirtual#5//方法java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
18:aload_1
19:invokevirtual#5//方法java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
22:invokevirtual#6//方法java/lang/StringBuffer.toString:()Ljava/lang/String;
所有4个版本似乎都在使用StringBuilder/StringBuffer优化,因此我很想知道从哪个Javac版本开始引入此更改?

以下引用:

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

当时,他们使用的是
StringBuffer
,而不是
StringBuilder

还引用了JDK1.0.2的一段话:

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


我查阅了Java语言规范第一版(1996年起)。不容易找到,但是。即使在那时,也有关于串联优化的文章:

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

该规范与
StringBuffer
相关,但是
StringBuilder
(当前JLS措辞所指)可能被认为性能更好,因为其方法不同步


然而,这并不意味着我们应该像往常一样依赖优化。例如,循环中的字符串连接不会得到优化。

JLS已经在一些答案中给出。我只想指出,StringBuffer()从1.0开始就存在了

StringBuilder()的版本为1.5。请参见相应Javadoc的
since:
部分

这并没有回答这个问题,但我只想补充一点,即在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
}

它实际上是一个用于字符串连接的
invokedynamic
字节码,因此它的实现现在是特定于JRE的,而不是编译器的。顺便说一句,默认策略是:
MH\u INLINE\u size\u EXACT

可能从一开始就有了……如果我没有弄错的话,Java 5更有用的是知道它们中的任何一个是否可以对使用循环构建的字符串执行此操作。请注意,编译器并不总是自动优化它。去年,我使用
String++
而不是
StringBuilder
,让一台带有Java8的Linux服务器崩溃了。我想构建一个相当大(大约300MB)的gnuplot文件。这涉及到一些逻辑,我必须并行构建两个150MB字符串,并在最后连接它们。使用
String#+
,需要半个小时的时间和所有可用的内存。使用
StringBuffer
,只需几秒钟,内存就大大减少了。这是一个不错的发现,但现在我不得不鄙视以前的老师,因为他们教我使用
StringBuffer
/
Builder
的无用的冗长语法-(我会试图找到一些安慰,相信它可能没有在早期版本的OpenJDK中得到优化,请不要破坏这一点:p@AaronStringBuilder通常应在构造复杂字符串时使用,例如在循环中(请参阅).噢,谢谢你的精确性!虽然这不是问题的重点,但我认为在你的答案中添加可能仍然很有趣,因为OP和其他读者可能会忽略这种优化并不总是可能的,并且可能会得出结论,因为我错误了,在任何地方使用字符串连接都是好的。@Aaron这并不是不必要的冗长。使用
StringBuilder
直接让您控制初始缓冲区大小。估计它可以节省您对底层字符数组进行一些昂贵的调整。@Aaron我不会称之为过早优化。如果循环进行了10000次串联,那么将
+
作为
StringBuilder
与默认缓冲区为16个字符。
+
实际上更快的一种情况是连接静态字符串值。在这种情况下,生成的字符串可以在编译时生成。对不起,您能解释一下允许的策略意味着什么吗?这是专为字符串连接进行的运行时优化吗?@glee8e我想我已经介绍了这里有一点主题:不需要深入研究JLS或字节码……只需检查Javadoc中的StringBuilder!它说的是
因为:1.5
。所以这个答案是最好的答案。(+1)