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.
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 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.
String vs String builder. which is faster? If stringbuilder then why use string
The advantage of String
is that it is immutable: once constructed, the contents of a string instance cannot change anymore. This means that you pass strings by reference without making copies all the time.
For example, suppose you would pass a StringBuilder
to a class. Then you could change the contents of that StringBuilder
afterwards, and confuse the class. So the class would need to make a copy to make sure that the content doesn't change without it knowing about it. With a String
this is not necessary, because a String
is immutable.
Now, when you're in the process of building a string, this immutability is actually a problem, because a new String
instance must be created for every concatenation. That's why the StringBuilder
class exists: it is an auxiliary class which is intended to build strings (hence the name).
In practice, it's often not necessary to use a StringBuilder
explicitly. The Java compiler will automatically use a StringBuilder
for you when you write things like String result = "some constant" + a + b;
. Only with complex building logic (using if
and for
blocks, for example) you need to do that yourself.
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
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.
Related Topics
How to Round Up the Result of Integer Division
What Are the Possible Values of the Hibernate Hbm2Ddl.Auto Configuration and What Do They Do
How to Get the Path of a Running Jar File
What Is the Volatile Keyword Useful For
Why Are Static Variables Considered Evil
Preparedstatement in Clause Alternatives
Converting Json Data to Java Object
How to Convert a Byte Array to a Hex String in Java
Stringbuilder VS String Concatenation in Tostring() in Java
How to Deal With "Java.Lang.Outofmemoryerror: Java Heap Space" Error
How to Fix a Nosuchmethoderror
Validating Input Using Java.Util.Scanner
When Do You Use Java'S @Override Annotation and Why
What Is the Point of the Diamond Operator (≪≫) in Java
How to Resolve Classnotfoundexception
Java Refuses to Start - Could Not Reserve Enough Space For Object Heap