StringBuilder vs String concatenation in toString() in Java
Version 1 is preferable because it is shorter and the compiler will in fact turn it into version 2 - no performance difference whatsoever.
More importantly given we have only 3
properties it might not make a
difference, but at what point do you
switch from concat to builder?
At the point where you're concatenating in a loop - that's usually when the compiler can't substitute StringBuilder
by itself.
String concatenation vs String Builder. Performance
The usual answer is that string concatenation is more efficient for between 4 to 8 strings. It depends on whose blog you read.
Don't write a test to decide on which method to use. If you are unsure of whether it will go over the magic limit, then just use StringBuilder.
Run this code to see the results for yourself:
const int sLen=30, Loops=5000;
DateTime sTime, eTime;
int i;
string sSource = new String('X', sLen);
string sDest = "";
//
// Time string concatenation.
//
sTime = DateTime.Now;
for(i=0;i<Loops;i++) sDest += sSource;
eTime = DateTime.Now;
Console.WriteLine("Concatenation took " + (eTime - sTime).TotalSeconds + " seconds.");
//
// Time StringBuilder.
//
sTime = DateTime.Now;
System.Text.StringBuilder sb = new System.Text.StringBuilder((int)(sLen * Loops * 1.1));
for(i=0;i<Loops;i++) sb.Append(sSource);
sDest = sb.ToString();
eTime = DateTime.Now;
Console.WriteLine("String Builder took " + (eTime - sTime).TotalSeconds + " seconds.");
//
// Make the console window stay open
// so that you can see the results when running from the IDE.
//
Console.WriteLine();
Console.Write("Press Enter to finish ... ");
Console.Read();
Ref. http://support.microsoft.com/kb/306822
Is it true that StringBuilder is slower than concatenate a dozen of strings?
String.Concat
is more efficient because it knows all the string lengths from the start. So it can allocate a single buffer with just the right length, copy the strings into it and return that buffer.
StringBuilder
has to allocate a small buffer, reallocating and copying everytime a call to Append
causes it to run out of space. The final call to ToString()
also has to allocate yet another buffer.
So use String.Concat
when you know in advance how many strings you have; use StringBuilder
when you don't.
In C#, chained calls to the + operator are automatically converted to a single call to String.Concat
.
Java: String concat vs StringBuilder - optimised, so what should I do?
I think the use of StringBuilder
vs +
really depends on the context you are using it in.
Generally using JDK 1.6 and above the compiler will automatically join strings together using StringBuilder
.
String one = "abc";
String two = "xyz";
String three = one + two;
This will compile String three
as:
String three = new StringBuilder().append(one).append(two).toString();
This is quite helpful and saves us some runtime. However this process is not always optimal. Take for example:
String out = "";
for( int i = 0; i < 10000 ; i++ ) {
out = out + i;
}
return out;
If we compile to bytecode and then decompile the bytecode generated we get something like:
String out = "";
for( int i = 0; i < 10000; i++ ) {
out = new StringBuilder().append(out).append(i).toString();
}
return out;
The compiler has optimised the inner loop but certainly has not made the best possible optimisations. To improve our code we could use:
StringBuilder out = new StringBuilder();
for( int i = 0 ; i < 10000; i++ ) {
out.append(i);
}
return out.toString();
Now this is more optimal than the compiler generated code, so there is definitely a need to write code using the StringBuilder
/StringBuffer
classes in cases where efficient code is needed. The current compilers are not great at dealing concatenating strings in loops, however this could change in the future.
You need to look carefully to see where you need to manually apply StringBuilder
and try to use it where it will not reduce readability of your code too.
Note: I compiled code using JDK 1.6, and and decompiled the code using the javap
program, which spits out byte code. It is fairly easy to interpret and is often a useful reference to look at when trying to optimise code. The compiler does change you code behind the scenes so it is always interesting to see what it does!
String concatenation performance: + vs StringBuilder
Taking @Holger's advice, I checked the bytecode for following code:
public class StringBM {
public String toStringPlus(String a) {
return "{a:" + a + ", b:" + ", c: " + "}";
}
public String toStringBuilder(String a) {
StringBuilder sb = new StringBuilder(100);
return sb.append("{a:").append(a)
.append(", b:")
.append(", c:")
.append("}")
.toString();
}
}
For toStringPlus
, I get
public java.lang.String toStringPlus(java.lang.String);
descriptor: (Ljava/lang/String;)Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: aload_1
1: invokedynamic #7, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
6: areturn
for toStringBuilder
:
public java.lang.String toStringBuilder(java.lang.String);
descriptor: (Ljava/lang/String;)Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=3, args_size=2
0: new #11 // class java/lang/StringBuilder
3: dup
4: bipush 100
6: invokespecial #13 // Method java/lang/StringBuilder."<init>":(I)V
9: astore_2
10: aload_2
11: ldc #16 // String {a:
13: invokevirtual #18 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
16: aload_1
17: invokevirtual #18 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: ldc #22 // String , b:
22: invokevirtual #18 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: ldc #24 // String , c:
27: invokevirtual #18 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: ldc #26 // String }
32: invokevirtual #18 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
35: invokevirtual #28 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
38: areturn
The +
version simply invokes dynamic function makeConcatWithConstants
.
Whereas the StringBuilder
version has to do it the 'honest' way.
I guess we can see why is +
faster now.
Performance between String.format and StringBuilder
After doing a little test with StringBuilder
vs String.format
I understood how much time it takes each of them to solve the concatenation. Here the snippet code and the results
Code:
String name = "stackover";
String lName = " flow";
String nick = " stackoverflow";
String email = "stackoverflow@email.com";
int phone = 123123123;
//for (int i = 0; i < 10; i++) {
long initialTime1 = System.currentTimeMillis();
String response = String.format(" - Contact {name=%s, lastName=%s, nickName=%s, email=%s, phone=%d}",
name, lName, nick, email, phone);
long finalTime1 = System.currentTimeMillis();
long totalTime1 = finalTime1 - initialTime1;
System.out.println(totalTime1 + response);
long initialTime2 = System.currentTimeMillis();
final StringBuilder sb = new StringBuilder(" - Contact {");
sb.append("name=").append(name)
.append(", lastName=").append(lName)
.append(", nickName=").append(nick)
.append(", email=").append(email)
.append(", phone=").append(phone)
.append('}');
String response2 = sb.toString();
long finalTime2 = System.currentTimeMillis();
long totalTime2 = finalTime2 - initialTime2;
System.out.println(totalTime2 + response2);
//}
After of run the code several times, I saw that String.format
takes more time:
String.format: 46: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
String.format: 38: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
String.format: 51: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
But if I run the same code inside a loop, the result change.
String.format: 43: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
String.format: 1: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
String.format: 1: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, email=stackoverflow@email.com, phone=123123123}
The first time String.format
runs it takes more time, after of that the time is shorter even though it does not become constant as a result of StringBuilder
As @G.Fiedler said: "String.format
has to parse the format string..."
With these results it can be said that StringBuilder
is more efficient thanString.format
stringbuilder versus string concat
I would use StringBuilder
here, just because it describes what you're doing.
For a simple concatenation of 3 or 4 strings, it probably won't make any significant difference, and string concatenation may even be slightly faster - but if you're wrong and there are lots of rows, StringBuilder
will start getting much more efficient, and it's always more descriptive of what you're doing.
Alternatively, use something like:
string html = string.Join("", dv.Cast<DataRowView>()
.Select(rv => rv.Row["X"]));
Note that you don't have any sort of separator between the strings at the moment. Are you sure that's what you want? (Also note that your code doesn't make a lot of sense at the moment - you're not using i
in the loop. Why?)
I have an article about string concatenation which goes into more detail about why it's worth using StringBuilder
and when.
EDIT: For those who doubt that string concatenation can be faster, here's a test - with deliberately "nasty" data, but just to prove it's possible:
using System;
using System.Diagnostics;
using System.Text;
class Test
{
static readonly string[] Bits = {
"small string",
"string which is a bit longer",
"stirng which is longer again to force yet another copy with any luck"
};
static readonly int ExpectedLength = string.Join("", Bits).Length;
static void Main()
{
Time(StringBuilderTest);
Time(ConcatenateTest);
}
static void Time(Action action)
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
// Make sure it's JITted
action();
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
action();
}
sw.Stop();
Console.WriteLine("{0}: {1} millis", action.Method.Name,
(long) sw.Elapsed.TotalMilliseconds);
}
static void ConcatenateTest()
{
string x = "";
foreach (string bit in Bits)
{
x += bit;
}
// Force a validation to prevent dodgy optimizations
if (x.Length != ExpectedLength)
{
throw new Exception("Eek!");
}
}
static void StringBuilderTest()
{
StringBuilder builder = new StringBuilder();
foreach (string bit in Bits)
{
builder.Append(bit);
}
string x = builder.ToString();
// Force a validation to prevent dodgy optimizations
if (x.Length != ExpectedLength)
{
throw new Exception("Eek!");
}
}
}
Results on my machine (compiled with /o+ /debug-
):
StringBuilderTest: 2245 millis
ConcatenateTest: 989 millis
I've run this several times, including reversing the order of the tests, and the results are consistent.
String builder vs string concatenation
In your particular example, none because the compiler internally uses StringBuilder
s to do String concatenation. If the concatenation occurred in a loop, however, the compiler could create several StringBuilder
and String
objects. For example:
String s= "" ;
for(int i= 0 ; i < 10 ; i++ )
s+= "a" ;
Each time line 3 above is executed, a new StringBuilder
object is created, the contents of s
appended, "a" appended, and then the StringBuilder
is converted into a String to be assigned back to s
. A total of 10 StringBuilder
s and 10 String
s.
Conversely, in
StringBuilder sb= new StringBuilder() ;
for(int i= 0 ; i < 10 ; i++ )
sb.append( "a" );
String s= sb.toString() ;
Only 1 StringBuilder
and 1 String
are created.
The main reason for this is that the compiler could not be smart enough to understand that the first loop is equivalent to the second and generate more efficient (byte) code. In more complex cases, it's impossible even for the smartest compiler to know. If you absolutely need this optimization, you have to introduce it manually by using StringBuilder
s explicitly.
.NET String concatenation (+ & +=) vs. StringBuilder
The problem is not so much that string concatenation is slow, it is more that repeated concatenation creates a lot of intermediate strings that need to be allocated and later garbage collected.
EDIT
Note that mystring += "a"
doesn't simple add "a" to the previous string. It creates a new string for the combination and points "mystring" to it, thereby discarding the previous value (if there are no more references to it).
END EDIT
A series of
string mystring = "something";
mystring += "something else";
mystring = mystring + "third";
will perform slower if you do each separate line as a StringBuilder Append followed by a .ToString() to get the result back in a string. You will only get a performance benefit if you use a single StringBuilder, Append() to it repeatedly and do a .ToString() at the very end.
StringBuilder sb = new StringBuilder();
sb.Append("something");
sb.Append("something else");
sb.Append("third");
string mystring = sb.ToString();
And then a StringBuilder has it's own overhead so that it will not benefit you if you have a small number of string-parts to join.
Note that the compiler optimizes away a concatenation in a single statement:
string mystring = "something" + "something else" + "third";
is fastest.
Related Topics
Capturing Binary Output from Process.Standardoutput
Date of Birth Validation Keeps Showing
Non-Static Method Requires a Target
Deserializing Xml to Objects in C#
How to Select an Option from Drop Down Using Selenium Webdriver C#
Create Xml Nodes Based on Xpath
Addeventhandler Using Reflection
The Entity Type Applicationuser Is Not Part of the Model for the Current Context
Serialize a Container of Enums as Strings Using JSON.Net
Open Default Mail Client Along with a Attachment
How to Find Out When You'Ve Been Loaded via Xml Serialization
Why Are C# Interface Methods Not Declared Abstract or Virtual
How to Access Configuration in Any Class in ASP.NET Core
Check If the Current User Is Administrator
C# Drag Drop Does Not Work on Windows 7
Loading a Full Hierarchy from a Self Referencing Table with Entityframework.Core