2

Found this excerpt from the book "Thinking in Java" written by Bruce Eckel.

If you try to take shortcuts and do something like append(a + ": " + c) , the compiler will jump in and start making more StringBuilder objects again.

Does that mean that we shouldn't replace a group of append operations with a single line of code; e.g result.append(i + ": " + 2*i + " ")?

StringBuilder result = new StringBuilder();
for(int i = 0; i < 25; i++) {
    result.append(i);
    result.append(": ");
    result.append(2*i);
    result.append(", ") 
}

Does the above statement hold true for Java 8 as well?

Excerpt from this answer on SO: (confused me even more)

At the point where you're concatenating in a loop - that's usually when the compiler can't substitute StringBuilder by itself.

Any aspect related to preferred coding style is also welcome.

Saurav Sahu
  • 13,038
  • 6
  • 64
  • 79

3 Answers3

3

This is not an optimisation the compiler will do for you efficiently. Stylistically, I would write it like this.

StringBuilder result = new StringBuilder();
for (int i = 0; i < 25; i++) {
    result.append(i).append(": ").append(2 * i).append(", ");
}

NOTE: IDEs, like IntelliJ, will detect and provide an auto-fix for this as it's a common translation.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Yes, *stylistically* definitely looks better than `result.append(i + ": " + 2*i + " ")`. But I am afraid the question is about concatenation. – Saurav Sahu Sep 03 '18 at 06:48
2

Basically, the compiler replaces instances of String concatenation with StringBuilders, so your line

result.append(i + ": " + 2*i + " ");

Is changed to

result.append(new StringBuilder().append(i).append(": ").append(2*i).append(" ").toString());

Like you can see, it just creates another StringBuilder, which is redundant since you already have one. On top of that, it needs to do so in every iteration of the loop, causing a lot of creation and garbage collection for nothing.

So yes, it would definitely be better to just append to the StringBuilder you already have directly, instead of concatenating. Whether or not you do this in a single fluent line is mostly a matter of preference.

I'm not sure what the answer you found means by "can't substitute StringBuilder". They probably meant that it won't re-use your existing builder (and instead create a new one).

This is still valid for Java 8, although since then there are alternative streaming methods, like one of the other answers shows.

TiiJ7
  • 3,332
  • 5
  • 25
  • 37
0

Yes, we should still use chained appends instead of string concatenation when performance is crucial.

However, whenever performance is not crucial, we should strive for code readability, clarity and reuse. Thus my stylistic choice would be:

IntStream
    .range(0, 25)
    .map(i, String.format("%d: %d", i, i*2)
    .collect(Collectors.joining(", "));
Torben
  • 3,805
  • 26
  • 31