何时应该明确使用StringBuilder?

21
据我了解,当我执行 String baz = "foo" + "bar" + "123"时,Java编译器会在内部用StringBuilder替换表达式。然而我们的Java老师告诉我们,总是明确使用StringBuilder是一个好习惯...
我是否正确地认为,只有在循环内进行连接时才需要明确使用StringBuilder,如在Stack Overflow问题的答案"String builder vs string concatenation"中所示?还有其他情况下,你应该明确使用StringBuilder而不是++=吗?

5
始终明确使用StringBuilder并不是一种良好的做法。为了获得0.0000000000001%的性能提升而牺牲代码的可读性是不值得的。只有在需要在循环中追加数千个字符串时,才应该使用StringBuilder。 - Konstantin V. Salikhov
2
我不确定为什么你的Java老师如此热衷于使用StringBuilder。虽然StringBuilder很酷,但Java在内部处理它。 - nafas
10
你的老师是错的,你是正确的。 - JB Nizet
6
你的观点是错误的,“String baz = "foo" + "bar" + "123"”将在编译时被替换为“String baz = "foobar123"”。在编译时,会进行编译时常量字符串拼接。此外,编译器可能会使用StringBuilder来替换非常量字符串拼接,但并不一定这样做。 - Boris the Spider
1
请访问http://www.javacodegeeks.com/2013/03/java-stringbuilder-myth-debunked.html。 - ThanksForAllTheFish
显示剩余2条评论
3个回答

37

它比“内部循环”更为通用——任何需要在多个语句上进行串联的时候,且不需要中间结果作为字符串。例如:

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而没有完全理解何时适用。


3
谢谢您和其他人提供的详细答案,现在一切都更加清晰了。 <离题>你是dernc.c库的作者Jon Skeet吗?因为我正在我的当前项目中使用该库的java端口 :) </离题> - user2711115
刚刚偶然发现这个问题 - 我不相信C#默认使用StringBuilder?有什么想法可以解释C#和Java之间的差异吗?我之前一直在想为什么C#不能自动处理这个问题。 - Ian
@Ian:C#使用String.Concat而不是StringBuilder,但原理是相同的。 - Jon Skeet
3
是的,我是 dernc (Adikted 的一部分) 的作者 - 尽管我记得 Simon Tatham 写了它所有复杂的部分... - Jon Skeet
1
Jon,说实话,对我来说String result = "Start" + (someCondition ? "Foo" : "") + (someOtherCondition ? "Bar" : "") + "End";比SB变量更易读...而且它更短更简洁。由于我的C背景和几十年使用三元运算符的经验,我认为像这样的语句很容易阅读。 - user719662
1
@vaxquis:对于所有同事来说,它是否更易读可能是另一回事 :) 我通常也喜欢三元运算符,但有限制。正如我所说,这些块中可能还有更多内容。 - Jon Skeet

1

奥比万曾说过只有西斯才会绝对思考或类似的话...

你知道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来增加清晰度 - 虽然我认为这样做可以模糊化事物。 - user719662

1

它们也适用于像 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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接