StringBuffer/StringBuilder efficiency

W

Wojtek

If I have the following:

StringBuilder text = new StringBuilder();
text.append("Hello");
text.append(" ");
text.append("World"):

or

StringBuilder text = new StringBuilder();
text.append("Hello" + " " + "World"):

I read somewhere at one time that the Java compiler will take the
second example and create the first example from it.

The second is easier to read but I have been using the first for better
efficiency.
 
M

markspace

Wojtek said:
I read somewhere at one time that the Java compiler will take the second
example and create the first example from it.


No, I don't think so. This example is pretty terrible, since I think
the compiler will make string constants from any concatenations it
finds. Thus "Hello"+" "+"World" just becomes the plain string "Hello
World".

I think you mean something like this:

String adjective = ...
StringBuilder text = new StringBuilder();
text.append("Hello " + adjective + " World");

This example will create something like this:

StringBuilder text = new StringBuilder();
//text.append("Hello " + adjective + " World");
StringBuilder $$temp = new StringBuilder();
$$temp.append("Hello");
$$temp.append(adjective);
$$temp.append(" World");
text.append($$temp.toString());

Note that it does create a second StringBuilder. Not very efficient.

The second is easier to read but I have been using the first for better
efficiency.


Yes, if you already have a StringBuilder, then the first form is more
efficient.
 
W

Wojtek

markspace wrote :
No, I don't think so. This example is pretty terrible, since I think the
compiler will make string constants from any concatenations it finds. Thus
"Hello"+" "+"World" just becomes the plain string "Hello World".
Guilty.

I think you mean something like this:

String adjective = ...
StringBuilder text = new StringBuilder();
text.append("Hello " + adjective + " World");

This example will create something like this:

StringBuilder text = new StringBuilder();
//text.append("Hello " + adjective + " World");
StringBuilder $$temp = new StringBuilder();
$$temp.append("Hello");
$$temp.append(adjective);
$$temp.append(" World");
text.append($$temp.toString());

Note that it does create a second StringBuilder. Not very efficient.

So it does not use the existing StringBuilder and just create.append()
calls? So if I have several of the concatenation lines I will have
several temporary StringBuilders created?

Yuck
 
M

markspace

Wojtek said:
So it does not use the existing StringBuilder and just create.append()
calls? So if I have several of the concatenation lines I will have
several temporary StringBuilders created?

Yuck


As far as I know, that's correct. If you're doing lots of heavy string
concatenation or other string manipulation, making one single
StringBuilder and doing it yourself can be a big performance boost.
 
J

Jussi Piitulainen

Wojtek said:
So it does not use the existing StringBuilder and just
create.append() calls? So if I have several of the concatenation
lines I will have several temporary StringBuilders created?

Yuck

You can chain the appends like so:

class Test {
public static void main(String [] args) {
System.out.println
(new StringBuilder()
.append("Arguments were ")
.append(args[0])
.append(" and ")
.append(args[1]));
}
}

End with .toString() if you want a String out of it.

I find this style less tedious to both read and write.
 
R

Roedy Green

The most efficient is new StringBuilder( n ) if you can give a good
estimate on final size. That way it will not waste ram, and will not
need to allocate a buffer and copy. I speeded up an app 10% by
optimising the ns.

If you use + + + you have no opportunity to optimise n on the hidden
buffer.

My IDE, IntelliJ lets you convert between various forms.
--
Roedy Green Canadian Mind Products
http://mindprod.com

"Don’t worry about people stealing an idea; if it’s original, you’ll have to shove it down their throats."
~ Howard Aiken (born: 1900-03-08 died: 1973-03-14 at age: 73)
 
R

Roedy Green

Nobody seems much interested in optimising concatenation or
StringBuilder. Maybe we need a benchmark to shine a spotlight on it.

Some possible optimisations:

1. compute the pieces to be concatenated, then sum the lengths THEN
allocate the StringBuilder exactly the right size.

2. If the buffer is full, then toString should steal the internal
char[] in the StringBuffer. Very rarely do you do anything with the
buffer after toString. In the rare instance you do, you can copy it
back from the toString string you keep a hidden reference to.

3. if you append a series of string literals, they could be prejoined
into one piece.



--
Roedy Green Canadian Mind Products
http://mindprod.com

"Don’t worry about people stealing an idea; if it’s original, you’ll have to shove it down their throats."
~ Howard Aiken (born: 1900-03-08 died: 1973-03-14 at age: 73)
 
R

Roedy Green

So it does not use the existing StringBuilder and just create.append()
calls? So if I have several of the concatenation lines I will have
several temporary StringBuilders created?

Yes, more than you might think. To find out for sure, decompile some
sample code. See http://mindprod.com/jgloss/decompiler.html

JAD is what I have used for this purpose.
--
Roedy Green Canadian Mind Products
http://mindprod.com

"Don’t worry about people stealing an idea; if it’s original, you’ll have to shove it down their throats."
~ Howard Aiken (born: 1900-03-08 died: 1973-03-14 at age: 73)
 
M

markspace

Wojtek said:
So it does not use the existing StringBuilder and just create.append()
calls? So if I have several of the concatenation lines I will have
several temporary StringBuilders created?

Yuck


I thought I'd also point out, that this is only "yuck" if the code in
question is part of the 20% of your application that gets executed
frequently. A few extra StringBuilder objects here and there won't hurt
anything. While making some "obvious" early optimization is ok, don't
feel the need to remove every single extra StringBuilder.

Just write code that you think looks correct, then profile it. When the
profiler finds sections that are executed frequently, then optimize the
bleep out of those parts. Don't waste time optimizing code that won't
be executed but occasionally.
 
L

Lew

I thought I'd also point out, that this is only "yuck" if the code in
question is part of the 20% of your application that gets executed
frequently.  A few extra StringBuilder objects here and there won't hurt
anything.  While making some "obvious" early optimization is ok, don't
feel the need to remove every single extra StringBuilder.

Just write code that you think looks correct, then profile it.  When the
profiler finds sections that are executed frequently, then optimize the
bleep out of those parts.  Don't waste time optimizing code that won't
be executed but occasionally.

Furthermore, the optimization of today could be the performance drag
of tomorrow. In principle HotSpot could dynamically perform many of
the optimizations we're discussing doing by hand. Maybe it does that
today, maybe it doesn't, but also maybe it will in the next release.
Naturally you cannot determine this by looking at the bytecode. You
might find yourself hand-optimizing something HotSpot would have done
for you, or will have done for you.

All the more reason to follow markspace's advice, with the addendum
that you should profile under JVM options similar to what you expect
in production with similar data input, accounting for HotSpot warmup.
(And with the same brand of JVM.)
 
W

Wojtek

markspace wrote :
I thought I'd also point out, that this is only "yuck" if the code in
question is part of the 20% of your application that gets executed
frequently. A few extra StringBuilder objects here and there won't hurt
anything. While making some "obvious" early optimization is ok, don't feel
the need to remove every single extra StringBuilder.

Just write code that you think looks correct, then profile it. When the
profiler finds sections that are executed frequently, then optimize the bleep
out of those parts. Don't waste time optimizing code that won't be executed
but occasionally.

Oh, I agree with you. It's not like I am going to refactor every
StringBuilder which is in the source code.

But if I am writing new code, then it is nice to know.
 
W

Wojtek

Roedy Green wrote :
Some possible optimisations:

1. compute the pieces to be concatenated, then sum the lengths THEN
allocate the StringBuilder exactly the right size.

Might be impossible to do with method calls.

text.append(myObj.getDescription());

or

myObj.appendDescription(text);
 
W

Wojtek

Wojtek wrote :
StringBuilder text = new StringBuilder();
text.append("Hello" + " " + "World"):

You know it might be better to forego StringBuilder entirely. Simply
use:

String text = "Value is: " + getValue() + " and it is " +
getValueState() + ". It can now be " + getValueAction();

and then the compiler will take the whole thing and make a single
StringBuilder construct out of it.

However using something like:

String text = "Value is: " + getValue();
text += " and it is " + getValueState();
text += ". It can now be "+ getValueAction();

might not cause it to happen.
 
M

markspace

Wojtek said:
You know it might be better to forego StringBuilder entirely. Simply use:

String text = "Value is: " + getValue() + " and it is " +
getValueState() + ". It can now be " + getValueAction();


Yes it is better. Consider breaking the lines for readability.

String text = "Value is: " + getValue()
+ " and it is " + getValueState()
+ ". It can now be " + getValueAction();

However using something like:

String text = "Value is: " + getValue();
text += " and it is " + getValueState();
text += ". It can now be "+ getValueAction();

might not cause it to happen.


That code will make at least 3 separate StringBuilders. The first
example is better, imo.
 
K

Kevin McMurtrie

StringBuilder text = new StringBuilder();
text.append("Hello" + " " + "World"):

This would probably optimize at compilation to:

StringBuilder text = new StringBuilder();
text.append("Hello World"):


But this:

StringBuilder text = new StringBuilder();
text.append("Hello World" + toString()):

Would compile to something like this:

StringBuilder text = new StringBuilder();
text.append(new StringBuilder()
.append("Hello World")
.append(toString())):


Probably not what you want.
 
L

Lew

Kevin said:
This would probably optimize at compilation to:

StringBuilder text = new StringBuilder();
text.append("Hello World"):

Not probably. Certainly, as required by the Java Language Specification.
But this:

StringBuilder text = new StringBuilder();
text.append("Hello World" + toString()):

Would compile to something like this:

StringBuilder text = new StringBuilder();
text.append(new StringBuilder()
.append("Hello World")
.append(toString())):

Actually not. 'text.append("Hello World" + toString()):' would throw compiler
errors. So would 'append(toString())'.
Probably not what you want.

You're correct that that wouldn't be what one wants.

Check out markspaces' post upthread (2009-09-24, 17:15Z) where he expressed
what you're going for. Your intent is correct.
 
D

Dave Searles

Lew said:
Actually not. 'text.append("Hello World" + toString()):' would throw
compiler errors. So would 'append(toString())'.

If in a static method or static initializer, yes. In a constructor or
instance method or initializer, though, "toString()" will call
this.toString(), which is sure to exist since toString() is a method of
Object.
 
R

Roedy Green

You might notice that JSP uses neither a StringBuffer or
StringBuilder. It uses some sort of stream, presumably a
StringWriter.

Has anyone looked at the code or done some experiments to decide when
to use StringWriter vs StringBuilder?
--
Roedy Green Canadian Mind Products
http://mindprod.com

"Don’t worry about people stealing an idea; if it’s original, you’ll have to shove it down their throats."
~ Howard Aiken (born: 1900-03-08 died: 1973-03-14 at age: 73)
 
R

Roedy Green

Not probably. Certainly, as required by the Java Language Specification.

I think you will find it optimises further to:

String text = "Hello World";

In other words it just moves a reference into the literal pool to the
variable 'text'.
--
Roedy Green Canadian Mind Products
http://mindprod.com

"Don’t worry about people stealing an idea; if it’s original, you’ll have to shove it down their throats."
~ Howard Aiken (born: 1900-03-08 died: 1973-03-14 at age: 73)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top