【问题标题】:Best practices/performance: mixing StringBuilder.append with String.concat最佳实践/性能:将 StringBuilder.append 与 String.concat 混合
【发布时间】:2012-04-22 03:54:19
【问题描述】:

我试图了解最佳实践是什么,以及为什么在不同情况下连接字符串文字和变量。例如,如果我有这样的代码

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String).append("CCCCCCCCCCC").append(D_String)
    .append("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .append("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");

这是这样做的方法吗?从this post,我注意到Strings 上的+ 运算符创建了一个新的StringBuilder 实例,连接操作数,并返回一个String 转换,这似乎比仅仅调用.append() 要多得多;所以如果这是真的,那是不可能的。但是String.concat() 呢?每次连接都使用.append() 是否合适?或者只是用于变量,文字可以附加.concat()

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String.concat("CCCCCCCCCCC")).append(D_String
    .concat("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .concat("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));

处理这些情况的最佳做法和性能的一般规则是什么?我对+ 的假设是否正确,它真的不应该被使用吗?

【问题讨论】:

  • 我想基本上你已经明白了。关于 String + “真的不应该使用”的意见不同。关键是你明白后果

标签: java string stringbuilder string-concatenation


【解决方案1】:

+运营商

String s = s1 + s2

这在幕后被翻译成:

String s = new StringBuilder(s1).append(s2).toString();

想象一下,如果你在这里有s1 + s2,它会增加多少额外的工作:

stringBuilder.append(s1 + s2)

代替:

stringBuilder.append(s1).append(s2)

带有+的多个字符串

值得注意的是:

String s = s1 + s2 + s3 + ... +sN

翻译成:

String s = new StringBuilder(s1).append(s2).append(s3)...apend(sN).toString();

concat()

String s = s1.concat(s2);

String 创建char[] 数组,可以同时容纳s1s2。将 s1s2 内容复制到这个新数组。实际上比+操作员需要更少的工作。

StringBuilder.append()

维护一个内部char[] 数组,该数组在需要时增长。如果内部char[] 足够大,则不会创建额外的char[]

stringBuilder.append(s1.concat(s2))

性能也很差,因为s1.concat(s2) 创建了一个额外的char[] 数组并将s1s2 复制到它只是为了将新数组内容复制到内部StringBuilderchar[]

话虽如此,您应该始终使用append() 并附加原始字符串(您的第一个代码 sn-p 是正确的)。

【讨论】:

  • 感谢您的帮助和深入的解释;这就是我真正需要的。
  • 虽然较新版本的编译器会自动将 + 运算符优化为字符串生成器,但假设它会像旧版本一样,不一定是一件好事。在整个讨论中,有一个非常重要的话题被忽略了,这实际上是 StringBuilder 的主要目的之一,即字符串池。使用字符串构建器将所有内容都保留为 char[],并且不会像 + 运算符在编译器优化之前所做的那样创建中间字符串(过去只是做一个 concat)。使用 concat 创建一个中间 String 对象,该对象被缓存但未使用。
  • 因此,如果我在几个不同的字符串上执行 一次性语句(不是跨方法的多个语句)连接。可以在 String 对象上使用+ 而不是为这个一次性连接创建StringBuilder,因为它基本上会做同样的事情?
  • 如果我只想连接一个字符,使用 .append('\n') 而不是 .append("\n") 会更好吗?因为字符是原始类型,而字符串是对象?
  • Effective Java 2-nd edition重复使用字符串连接运算符连接 n 个字符串需要 n 中的时间二次方。 所以它仍然相关吗?
【解决方案2】:

编译器优化 + 连接。

所以

int a = 1;
String s = "Hello " + a;

变成了

new StringBuilder().append("Hello ").append(1).toString();

有一个很好的话题here 解释了为什么应该使用 + 运算符。

【讨论】:

  • 编译器实际上会将其优化为String s = "Hello World";,因为您使用的是文字。
  • @ColinD:+1。刚刚修改了我的 sn-p。
  • "Hello" 将在 StringBuilder 的构造函数中
【解决方案3】:

优化由编译器自动完成。

Java2 编译器会自动转换以下内容:

String s = s1 + s2; 

String s = (new StringBuffer()).append(s1).append(s2).toString();

直接取自 Oracles 网站上的 Java Best Practices

【讨论】:

    【解决方案4】:

    您应该始终使用append

    concat 创建一个新字符串,所以我认为它很像+

    如果你 concat 或使用 + 与 2 final String JVM 可以进行优化,因此在这种情况下与进行追加相同。

    【讨论】:

      【解决方案5】:

      如果您恰好连接两个字符串,则使用 String.concat(通过创建一个适合两个字符串的新字符数组并将两个字符串的字符数组复制到其中来创建一个新字符串)。

      如果在一行中连接多个(两个以上)字符串,请使用 + 或 StringBuilder.append,这无关紧要,因为编译器会将 + 转换为 StringBuilder.append。这对多个字符串很有用,因为它维护一个根据需要增长的 char 数组。

      如果您在多行上连接多个字符串,请创建一个 StringBuilder 并使用附加方法。最后,当您完成将字符串附加到 StringBuilder 时,使用它的 .toString() 方法从中创建一个字符串。 对于多行连接,这比第二种方法更快,因为第二种方法会在每一行上创建一个新的 StringBuilder,附加字符串,然后再转换回 String,而第三种方法只使用一个 StringBuilder。

      【讨论】:

        【解决方案6】:

        我个人更喜欢Strings.format(),简单易读的一行string formatter

        String b = "B value";
        String d = "D value";
        String fullString = String.format("A %s C %s E F", b, d);
        // Output: A B value C D value E F
        

        【讨论】:

          【解决方案7】:

          使用+ 操作符是最佳实践,它也简单易读。

          Java 语言为字符串提供了特殊的支持 连接运算符 ( + ),以及将其他对象转换为 字符串。字符串连接是通过 StringBuilder(或StringBuffer)类及其append方法。

          官方文档:https://docs.oracle.com/javase/8/docs/api/java/lang/String.html

          【讨论】:

            【解决方案8】:

            在字节码级别并没有什么不同,我们并没有影响那里的效率。在执行字节码级别的情况下,必须通过调用append的方式对+进行非内联运算符重载方法。然后在汇编语言级别(Java是用C编写的,C产生类似于汇编的程序集,会有额外的寄存器调用来存储+堆栈中的方法调用,并且会有额外的push。(实际上,交叉编译器可能会优化+运算符调用,在这种情况下,它与效率没有区别。)

            最好有一种方法来提高可读性。 :)

            【讨论】:

              【解决方案9】:

              所有答案都非常好且易于解释。但我觉得探索其他字符串连接技术也会有所帮助 - Guava Joiner、Streams、String.format 等。

              有关每种连接技术性能的完整详细信息java-string-concatenation-which-way-is-best

              简而言之,连接性能随 no 变化。要连接的字符串。例如 - 要连接 1-10 个字符串,这些技术效果最好 - StringBuilder、StringBuffer 和 Plus 运算符。 并连接 100 个字符串 - Guava Joiner,apache 的 stringsUtils 库也很好用。

              请浏览上述博客。它确实很好地解释了性能效率。

              谢谢。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2011-04-29
                • 2011-03-06
                • 2012-01-17
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-09-10
                相关资源
                最近更新 更多