【问题标题】:String concatenation in Java - when to use +, StringBuilder and concat [duplicate]Java中的字符串连接-何时使用+,StringBuilder和concat [重复]
【发布时间】:2011-12-10 16:52:38
【问题描述】:

什么时候应该使用+来连接字符串,什么时候首选StringBuilder,什么时候适合使用concat。

我听说 StringBuilder 更适合循环内的连接。为什么会这样?

谢谢。

【问题讨论】:

  • 首先想到的是,每次您使用纯字符串时,您都会分配一个对象(为 GarbageCollector 提供工作),而使用 StringBuilder 或 StringBuffer 可以让您使用单个对象。

标签: java string


【解决方案1】:

现代 Java 编译器通过 StringBuilder 的附加来转换您的 + 操作。我的意思是说,如果你这样做str = str1 + str2 + str3,那么编译器将生成以下代码:

StringBuilder sb = new StringBuilder();
str = sb.append(str1).append(str2).append(str3).toString();

您可以使用 DJ 或 Cavaj 反编译代码来确认这一点 :) 所以现在更多的是选择问题而不是使用 + 或 StringBuilder 的性能优势:)

但是考虑到编译器不会为您执行此操作的情况(如果您使用任何私有 Java SDK 执行此操作,那么它可能会发生),那么 StringBuilder 肯定是您最终避免大量不必要的 @ 987654323@ 个对象。

【讨论】:

  • 是的,但是如果您在循环中使用+,运行时将为每次迭代创建一个新的StringBuilder,从而导致严重的性能损失。
  • 您可以在循环开始之前创建 STingBuilder。如果您每次都在循环中创建 StringBuilder,那么您无论如何都会丢失 StringBuilder 的 previos 数据。
  • @Sahil:编译器或优化器可能会解决这个问题。
  • str = new StringBuilder(str1).append(str2).append(str3).toString();它会在性能问题上产生影响吗?
  • 如果你想实现 str1、str2 和 str3 的串联,那么这是最好的方法。
【解决方案2】:

我倾向于在关注性能的代码路径上使用StringBuilder。循环中的重复字符串连接通常是一个不错的选择。

首选StringBuilder 的原因是+concat 每次调用它们时都会创建一个新对象(前提是右侧参数不为空)。这可以很快加起来很多对象,几乎所有这些都是完全不必要的。

正如其他人所指出的,当您在同一语句中多次使用+ 时,编译器通常可以为您优化。然而,根据我的经验,当连接发生在单独的语句中时,这个论点并不适用。它当然对循环没有帮助。

说了这么多,我认为首要任务应该是编写清晰的代码。有一些适用于 Java 的出色分析工具(我使用 YourKit),它们可以很容易地查明性能瓶颈并仅优化重要的部分。

附:我从来不需要使用concat

【讨论】:

  • 我只用过一次concat(),那是用方法引用替换str -> "foo" + str"foo"::concat
【解决方案3】:

来自Java/J2EE Job Interview Companion

String

String 是不可变的:您不能修改 String 对象,但可以通过创建新实例来替换它。创建一个新实例相当昂贵。

//Inefficient version using immutable String
String output = "Some text";
int count = 100;
for (int i = 0; i < count; i++) {
    output += i;
}
return output;

上面的代码将构建 99 个新的 String 对象,其中 98 个将被立即丢弃。创建新对象效率不高。

StringBuffer/StringBuilder

StringBuffer 是可变的:当你想修改内容时使用StringBufferStringBuilderStringBuilder 是在 Java 5 中添加的,它在所有方面都与 StringBuffer 相同,只是它不是同步的,这使得它稍微快一些,但代价是不是线程安全的。

//More efficient version using mutable StringBuffer
StringBuffer output = new StringBuffer(110);
output.append("Some text");
for (int i = 0; i < count; i++) {
  output.append(i);
}
return output.toString();

上面的代码只创建了两个新对象,StringBuffer 和最终返回的StringStringBuffer 会根据需要扩展,但代价高昂,因此最好从一开始就以正确的大小初始化 StringBuffer,如图所示。

【讨论】:

  • 图书链接加 1。 (无法将+ 符号添加为“评论不能包含该内容”:))
【解决方案4】:

如果所有连接的元素都是常量(例如:"these" + "are" + "constants"),那么我更喜欢 +,因为编译器会为您内联连接。否则,使用 StringBuilder 是最有效的方法。

如果您将 + 与非常量一起使用,编译器也会在内部使用 StringBuilder,但调试会变得很糟糕,因为使用的代码不再与您的源代码相同。

【讨论】:

    【解决方案5】:

    我的建议如下:

    • +:在连接 2 或 3 个字符串时使用,以保持代码简洁易读。
    • StringBuilder:在构建复杂的字符串输出或关注性能时使用。
    • String.format:您在问题中没有提到这一点,但它是我创建字符串的首选方法,因为它使代码在我看来最易读/最简洁,并且对日志语句特别有用。
    • concat:我认为我没有理由使用它。

    【讨论】:

    • concat() 如果你要连接两个字符串,那该死的快。
    【解决方案6】:

    如果您进行大量操作,请使用StringBuilder通常一个循环很好地说明了这一点。

    这样做的原因是,使用普通的串联会产生大量不易“扩展”的中间String 对象(即每个串联操作都会产生一个副本,需要内存和CPU 时间制作)。另一方面,StringBuilder 只需要在某些情况下复制数据(在中间插入一些东西,或者因为结果变大而不得不调整大小),所以它节省了那些复制操作。

    使用concat() 与使用+ 相比并没有真正的好处(单个+ 可能会稍微快一点,但一旦你使用a.concat(b).concat(c),它实际上会比a + b + c 慢)。

    【讨论】:

      【解决方案7】:

      编译器的性能增益适用于串联常量。 其余的使用实际上比直接使用 StringBuilder 慢。

      使用“+”没有问题,例如用于为异常创建消息,因为它不经常发生并且应用程序 si 目前已经以某种方式搞砸了。 避免在循环中使用“+”。

      要创建有意义的消息或其他参数化字符串(例如 Xpath 表达式),请使用 String.format - 它的可读性要好得多。

      【讨论】:

        【解决方案8】:

        对单个语句使用 +,对多个语句/循环使用 StringBuilder。

        【讨论】:

          【解决方案9】:

          我建议使用 concat 进行两个字符串连接,否则使用 StringBuilder,请参阅我对 concatenation operator (+) vs concat() 的解释

          【讨论】:

            猜你喜欢
            • 2011-12-01
            • 2011-07-22
            • 2015-12-23
            • 2010-12-04
            • 1970-01-01
            • 2019-03-09
            • 2014-02-19
            • 1970-01-01
            相关资源
            最近更新 更多