【问题标题】:Is chain of StringBuilder.append more efficient than string concatenation?StringBuilder.append 链是否比字符串连接更有效?
【发布时间】:2011-11-27 00:39:24
【问题描述】:

根据名为 使用 .append 方法链而不是字符串连接的 Netbeans 提示

在调用 StringBuilder 或 StringBuffer 的 append 方法的参数中查找字符串连接。

StringBuilder.append() 真的比字符串连接更高效吗?

代码示例

StringBuilder sb = new StringBuilder();
sb.append(filename + "/");

对比

StringBuilder sb = new StringBuilder();
sb.append(filename).append("/");

【问题讨论】:

  • @Zaki:这些基准在实际中并不是那么有用。更有用的是分析您的应用程序以查看它是否确实存在性能瓶颈。并为您的特定用例选择合适的算法和数据结构。

标签: java


【解决方案1】:

您必须平衡可读性和功能性。

假设您有以下内容:

String str = "foo";
str += "bar";
if(baz) str += "baz";

这将创建 2 个字符串构建器(实际上您只需要 1 个)加上一个额外的字符串对象用于临时。如果你去,你会更有效率:

StringBuilder strBuilder = new StringBuilder("foo");
strBuilder.append("bar");
if(baz) strBuilder.append("baz");
String str = strBuilder.toString();

但就风格而言,我认为第一个看起来还不错。对我来说,单个对象创建的性能优势似乎很小。现在,如果不是 3 根琴弦,而是 10、20 或 100 根琴弦,我会说性能胜过风格。如果它在一个循环中,我肯定会使用字符串生成器,但我认为只需几个字符串就可以使用“草率”的方式使代码看起来更干净。但是……这里面潜伏着一个非常危险的陷阱!请继续阅读下面的内容(暂停以制造悬念...... dun dun dunnnn)

有些人说要始终使用显式字符串生成器。一个理由是您的代码将继续增长,并且它通常会以与它已经相同的方式这样做(即他们不会花时间重构。)因此您最终会得到每条创建的 10 或 20 条语句当你不需要他们自己的建设者。因此,为了从一开始就防止这种情况,他们说始终使用显式构建器。

因此,虽然在您的示例中,它不会特别快,但当将来有人决定他们想要一个文件扩展名或类似的东西时,如果他们继续使用字符串连接而不是 StringBuilder,他们'最终会遇到性能问题。

我们还需要考虑未来。假设您在 JDK 1.1 中编写 Java 代码,并且您有以下方法:

public String concat(String s1, String s2, String s3) {
    return s1 + s2 + s3;
}

那时会很慢,因为没有StringBuilder。

然后在 JDK 1.3 中,您决定使用 StringBuffer 来提高速度(StringBuilder 仍然不存在)。你这样做:

public String concat(String s1, String s2, String s3) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);
    sb.append(s2);
    sb.append(s3);
    return sb.toString();
}

它变得更快。太棒了!

现在JDK 1.5出来了,随之而来的是StringBuilder(比StringBuffer更快)和自动转换

return s1 + s2 + s3;

return new StringBuilder().append(s1).append(s2).append(s3).toString();

但您并没有获得这种性能优势,因为您明确地使用了 StringBuffer。因此,通过变得聪明,当 Java 变得比你更聪明时,你已经对性能造成了影响。所以你必须记住,有些事情是你不会想到的。

【讨论】:

  • @corsiKa :我的循环运行了 16 次,这就是我在循环中所做的 - str+=som_value。我的是jdk1.6。那么我是否应该使用 StringBuilder。
  • @Ashwin 我个人会在那里使用 StringBuilder。有必要吗?我想这取决于循环运行的频率。如果您正在构建哈希的输出,那么您可以期望做很多事情。一定要加快速度。如果您正在构建程序的标题并且它只被调用一次,可能没什么大不了的。
【解决方案2】:

嗯,你的第一个例子基本上是由编译器翻译成类似的东西:

StringBuilder sb = new StringBuilder();
sb.append(new StringBuilder().append(filename).append("/").toString());

所以是的,这里有一定的低效率。但是,它在你的程序中是否真的很重要是一个不同的问题。除了是有问题的风格(提示:主观)之外,它通常只在你在一个紧密的循环中这样做时才重要。

【讨论】:

  • 字符串连接实际上是使用StringBuilder 完成的吗?让String 包含一个接受两个字符串并将它们连接起来的构造函数似乎更明智(可能还有3-4 个字符串的版本,以及一个接受String[] 的版本)。给定要连接的字符串,可以在为结果的后备存储分配空间之前添加它们的长度,从而一次性准确地分配适量的空间。编译器不这样做似乎很疯狂。
【解决方案3】:

到目前为止,没有一个答案明确解决了提示所针对的具体情况。这并不是说总是使用StringBuilder#append 而不是串联。但是,如果您已经在使用StringBuilder,那么混合串联是没有意义的,因为它会创建一个冗余的StringBuilder(参见Dirk's answer)和一个不必要的临时String 实例。

几个答案已经讨论了为什么建议的方法更有效,但重点是,如果您已经有一个 StringBuilder 实例,只需调用 append 即可。由于您调用append,它的可读性(在我看来,显然是编写 NetBeans 提示的人),而且效率更高。

【讨论】:

  • 在某些情况下,先进行连接可能会有所帮助;其中大多数是这样的场景,如果字符串的长度有一些随机变化,那么预连接更有效的概率会非常低,但是对于字符串长度的某些特定组合,它可能每次都“获胜”。如果第一个AppendStringBuilder/StringBuffer 扩展为不足以容纳第二个的大小,则由连接引起的额外分配可能比SB 使用的更便宜。一种罕见的情况,但有可能。
  • @supercat 这是一个有趣的观点,也是一个很好的例子,说明了为什么在优化代码(并使用代表性数据)时应该始终进行衡量。
  • 我自己的偏好是诉诸我的主要规则:“做有意义的事”。在大多数情况下,无论哪种方式都不会产生巨大的性能差异,因此请在连接更清晰且不太可能明显影响性能时支持连接。如果多个连接必须出现在不同的语句中,我更喜欢StringBuilder,但当它们可以出现在一个表达式中时,我更喜欢那样。除非字符串很大,否则易读性应该比性能更重要。
【解决方案4】:

理论上,是的。因为 String 对象是不可变的:一旦构造它们就不能再更改。所以使用“+”(连接)基本上每次都会创建一个新对象。

实际上没有。编译器足够聪明,可以用 StringBuilder 附加项替换所有“+”。

更详细的解释: http://kaioa.com/node/59

PS:Netbeans???加油!

【讨论】:

  • Come on! ?那你会推荐什么?
  • 您的第二句话暗示它们都被放入一个StringBuilder中。这是不准确的。如果你有String s = "a" + "b"; s += "c";,你会得到 2 个字符串生成器,而不是 1 个。
  • 我会推荐 IntelliJ。从 2003 年到 1012 年使用 eclipse,然后切换。性能大幅提升。关于主题:这些天确实是字符串连接。
  • 这里也一样。我是 Eclipse 的忠实粉丝,直到我“只尝试了几天”IntelliJ,因为我的同事一直在唠叨。我从未回头。
【解决方案5】:

使用此函数连接两个字符串会更快。

但是,如果您有多个字符串或不同的数据类型,则应显式或隐式使用 StringBuilder。将 + 与字符串一起使用是在隐式使用 StringBuilder。

【讨论】:

    【解决方案6】:

    如果您使用大量连接和非常长的字符串,它只会更有效。对于一般用途,例如在您的示例中创建文件名,任何字符串连接都很好并且更具可读性。

    无论如何,应用程序的这一部分不太可能成为性能瓶颈。

    【讨论】:

      猜你喜欢
      • 2021-06-06
      • 2022-11-23
      • 2015-05-17
      • 2019-07-05
      • 2010-09-30
      • 2020-11-22
      • 1970-01-01
      相关资源
      最近更新 更多