21

As I understand it, when I do String baz = "foo" + "bar" + "123" the Java compiler internally replaces the expression with a StringBuilder. However our Java teacher told us that it is good practice to always use a StringBuilder explicitly...

Am I correct in assuming I will only need to explicitly use StringBuilder when concatenating inside loops as indicated in an answer to Stack Overflow question String builder vs string concatenation? Are there other cases where you should explicitly use a StringBuilder instead of + or +=?

Community
  • 1
  • 1
user2711115
  • 457
  • 3
  • 18
  • 5
    `to always use a StringBuilder explicitly` - it isn't good practice. You will sacrifice code readability for 0.0000000000001% performance gain. Use StringBuilder when you are going to append in a loop thousands of strings. – Konstantin V. Salikhov Jul 04 '14 at 09:53
  • 2
    I'm not sure why you java teacher is so keen on using StringBuilder. StringBuilder is cool and all but java deals with it internally. – nafas Jul 04 '14 at 09:53
  • 10
    Your teacher is wrong. You are correct. – JB Nizet Jul 04 '14 at 09:53
  • 6
    You are wrong, `String baz = "foo" + "bar" + "123"` will be replaced with `String baz = "foobar123"` at compile time. Compile time constant string concatenation is is done _at compile time_. Also, the compiler _may_ replace non-constant string concatenation with a `StringBuilder` but is under no obligation to do so. – Boris the Spider Jul 04 '14 at 11:45
  • See also http://stackoverflow.com/questions/11942368/why-using-stringbuilder-explicitly-if-the-compiler-converts-string-concatenation – Raedwald Jul 04 '14 at 13:09
  • 1
    And http://www.javacodegeeks.com/2013/03/java-stringbuilder-myth-debunked.html – ThanksForAllTheFish Jul 04 '14 at 13:24
  • 1
    How is this not a duplicate nearly 6 years after Stack Overflow was launched? – Peter Mortensen Jul 04 '14 at 22:45

3 Answers3

37

It's more general than "inside loops" - it's any time you want to do concatenation over multiple statements, and don't need the intermediate result as a string. For example:

StringBuilder builder = new StringBuilder("Start");
if (someCondition) {
    builder.append("Foo");
}
if (someOtherCondition) {
    builder.append("Bar");
}
builder.append("End");
String result = builder.toString();

While you could write that as:

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

... that becomes hard to read. And if there are more statements within the if bodies, it may not even be feasible.

To correct something within your question though:

As I understand it, when I do String baz = "foo" + "bar" + "123" the java compiler internally replaces the expression with a StringBuilder.

No, when you write that expression the compiler recognizes that it's a compile-time constant, and replaces it with

String baz = "foobar123";

That's a very good reason not to explicitly use a StringBuilder - the code above is clearly more efficient at execution time than

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

When it isn't a compile-time constant, the Java compiler will perform the concatenation using a StringBuilder, usually leaving you with easier-to-understand code than with the explicit use of StringBuilder, but with no performance hit. I suspect your teacher either doesn't properly understand string concatenation, or simply read somewhere else that you should use StringBuilder without fully understanding when it's appropriate.

Natan Streppel
  • 5,759
  • 6
  • 35
  • 43
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    Thank you and everyone else for the detailed answer, everything is much clearer now. are you Jon Skeet the author of dernc.c library? because I'm using a java port of that in my current project :) – user2711115 Jul 04 '14 at 10:13
  • Just stumbled across this - I don't believe C# uses a StringBuilder underneath by default? Any idea why the difference between C# and Java - I've previously wondered why C# doesn't just take care of this for you. – Ian Jul 04 '14 at 11:57
  • @Ian: C# uses `String.Concat` rather than a `StringBuilder`, but it's the same sort of principle. – Jon Skeet Jul 04 '14 at 12:46
  • 3
    @user2711115: Yes, I'm the author of dernc (as part of Adikted) - although I seem to remember that Simon Tatham wrote all the tricky bits of it... – Jon Skeet Jul 04 '14 at 12:47
  • 1
    Jon, honestly, `String result = "Start" + (someCondition ? "Foo" : "") + (someOtherCondition ? "Bar" : "") + "End";` is actually *more* readable to me than SB variant... and it's a lot shorter and more concise too. C background and decades of using ternary make it routine to read statements like that without any effort IMO. –  Jul 04 '14 at 16:04
  • 1
    @vaxquis: Whether it would be more readable to all your colleagues may be a different matter :) I'm generally A fan of the ternary operator too, but there are limits. And as I say, there could be more within those blocks. – Jon Skeet Jul 04 '14 at 17:41
1

Obi Wan has said that only Sith thinks in absolutes or something similar...

It's good you know that Java compiler internally replaces "+" on Strings with the usage of the StringBuilder. This is what are the compilers for: to make the life easier.

Unless you have loops, as in linked case, or conditionals from Jon Skeet's example, it's primarily the matter of readibility and the ease of maintanance.

Replacing

return "User " + userName + " said";

with

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

makes the code longer, probably harder to modify, is more likely to force line breaks, and gives you more performance.

However, when the addition apply not only to the strings, but there are numbers involved, probably the solution with StringBuilder sometimes may be more readable.

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

may be more confusing as:

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

But it's primarily the matter of opinion and coding style. "Should" is not a good word here.

Danubian Sailor
  • 1
  • 38
  • 145
  • 223
  • I'd only repeat myself - `return "User" + a + b + " said: " + (c + d);` is still much more readable to me than the latter version, especially if the numbers are named sensibly - also note that you seldom use two numbers next to each other *without any separator in between*; I haven't seen any real-life example that would actually use SB to *increase* clarity - I'd say it's good to *obfuscate* things, though. –  Jul 04 '14 at 16:06
1

They're also good for implementing things like C#'s 'out' keyword with a String. Example

public int getInt(StringBuilder error)
{
    int retVal = 0;

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

    return retVal;
}
David Carpenter
  • 1,389
  • 2
  • 16
  • 29