什么时候应该明确使用 StringBuilder? [复制]

Posted

技术标签:

【中文标题】什么时候应该明确使用 StringBuilder? [复制]【英文标题】:When should you explicitly use a StringBuilder? [duplicate] 【发布时间】:2014-08-25 15:01:09 【问题描述】:

据我了解,当我执行 String baz = "foo" + "bar" + "123" 时,Java 编译器会在内部将表达式替换为 StringBuilder。然而,我们的 Java 老师告诉我们,始终明确使用 StringBuilder 是一种好习惯...

我是否正确地假设我将在连接内部循环时需要显式使用 StringBuilder,如 an answer to Stack Overflow question String builder vs string concatenation 中所示?在其他情况下,您应该明确使用StringBuilder 而不是++=

【问题讨论】:

to always use a StringBuilder explicitly - 这不是一个好习惯。您将牺牲代码可读性以获得 0.0000000000001% 的性能提升。当您要在循环中追加数千个字符串时,请使用 StringBuilder。 我不知道你的java老师为什么这么热衷于使用StringBuilder。 StringBuilder 很酷,除了 java 之外,其他都在内部处理它。 你的老师错了。你是对的。 你错了,String baz = "foo" + "bar" + "123"在编译时会被替换为String baz = "foobar123"。编译时常量字符串连接是在在编译时完成的。此外,编译器可以StringBuilder 替换非常量字符串连接,但没有义务这样做。 还有javacodegeeks.com/2013/03/java-stringbuilder-myth-debunked.html 【参考方案1】:

它比“内部循环”更通用 - 任何时候您都想对多个语句进行连接,并且不需要将中间结果作为字符串。例如:

StringBuilder builder = new StringBuilder("Start");
if (someCondition) 
    builder.append("Foo");

if (someOtherCondition) 
    builder.append("Bar");

builder.append("End");
String result = builder.toString();

虽然你可以写成:

String result = "Start" + (someCondition ? "Foo" : "")
    + (someOtherCondition ? "Bar" : "") + "End";

...这变得难以阅读。如果if 正文中有更多的语句,它甚至可能不可行。

要更正您的问题中的某些内容:

据我了解,当我执行 String baz = "foo" + "bar" + "123" 时,java 编译器会在内部将表达式替换为 StringBuilder。

不,当您编写该表达式时,编译器会识别出它是一个编译时常量,并将其替换为

String baz = "foobar123";

这是一个很好的理由显式使用StringBuilder - 上面的代码在执行时显然比

String baz = new StringBuilder("foo").append("bar").append("123").toString();

当它不是一个编译时常量时,Java 编译器将使用StringBuilder 执行连接,通常给您留下比显式使用更容易理解的代码StringBuilder,但性能没有受到影响。我怀疑您的老师要么没有正确理解字符串连接,要么只是在其他地方阅读了您应该使用StringBuilder 而没有完全理解何时它是合适的。

【讨论】:

感谢您和其他所有人的详细回答,现在一切都清楚多了。 你是 dernc.c 库的作者 Jon Skeet 吗?因为我在当前项目中使用了它的 java 端口:) 刚刚偶然发现 - 我不相信 C# 默认使用 StringBuilder?任何想法为什么 C# 和 Java 之间的区别 - 我以前想知道为什么 C# 不只是为你处理这个问题。 @user2711115:是的,我是 dernc 的作者(作为 Adikted 的一部分)——尽管我似乎记得 Simon Tatham 写了所有棘手的部分...... 乔恩,老实说,String result = "Start" + (someCondition ? "Foo" : "") + (someOtherCondition ? "Bar" : "") + "End"; 实际上比 SB 变体对我来说更多可读......而且它也更短更简洁。 C 背景和数十年的三进制使用使得无需任何努力 IMO 即可轻松阅读此类语句。 @vaxquis:对于所有同事来说,它是否更具可读性可能是另一回事:) 我通常也是三元运算符的粉丝,但有限制。正如我所说,这些区块中可能还有更多。【参考方案2】:

欧比万说过,只有西斯会以绝对的方式思考或类似的东西......

很高兴您知道 Java 编译器在内部使用 StringBuilder 替换字符串上的“+”。这就是编译器的目的:让生活更轻松。

除非你有循环,比如链接的情况,或者 Jon Skeet 的例子中的条件,这主要是可读性和易于维护的问题。

更换

return "User " + userName + " said";

new StringBuilder().append("User ").append(userName).append(" said").toString();

使代码更长,可能更难修改,更有可能强制换行,并为您提供更高的性能。

但是,当加法不仅适用于字符串,还涉及数字时,StringBuilder 的解决方案有时可能更具可读性。

return "User" + a + b + " said: " + (c + d);

可能更令人困惑:

return new StringBuilder().append("User ").append(a).append(b)
  .append(" said: ").append(c+d).toString();  

但这主要是意见和编码风格的问题。 “应该”在这里不是个好词。

【讨论】:

我只想重复一遍 - return "User" + a + b + " said: " + (c + d); 对我来说仍然比后一个版本更具可读性,特别是如果数字命名合理 - 另请注意,您很少使用两个数字相邻中间没有任何分隔符;我还没有看到任何实际使用 SB 来提高清晰度的真实示例 - 不过,我会说混淆事物是件好事。【参考方案3】:

它们也很适合用字符串实现诸如 C# 的“out”关键字之类的东西。示例

public int getInt(StringBuilder error)

    int retVal = 0;

    if (someErrorOccured)
        error.append("Couldn't get int because of...");
    else
        retVal = whatItsSupposedToBe;

    return retVal;

【讨论】:

以上是关于什么时候应该明确使用 StringBuilder? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

我啥时候应该明确使用 `this` 指针?

什么是空间索引,我应该什么时候使用它?

Stringbuffer、Stringbuilder啥时候用? [复制]

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

C# String与StringBuilder

String,StringBuilder性能对照