Java Compiler replacing StringBuilder with + concatenation - java

Here's some simple Java code:
String s = new StringBuilder().append("a").append("b").append("c").toString();
I compile it with JRE 1.6, and I observe the following in the decompiled class file:
String s = "a" + "b" + "c";
I had the following questions:
Why does the compiler choose '+' over StringBuilder?
Do we have any official Java specification that justifies this behavior?
Does it really make sense to use StringBuilder in such cases, where we know compiler is going to change it anyway?

It's the other way round. + for String is implemented using StringBuilder (or StringBuffer) behind the scenes (see http://docs.oracle.com/javase/7/docs/api/java/lang/String.html or http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.18.1).
Thus, once they're compiled, your two code snippets are indistinguishable. The decompiler has to make a guess at the original form.

The decompiler must have assumed that the bytecode instructions to call append over and over resulted from source code that used the + operator.
Section 15.18.1 of the JLS specifies that a compiler can use a StringBuffer or similar means to implement the + operator between Strings:
An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.
The StringBuilder class is a "similar technique".
In this case, you can use either technique to concatenate your strings. If you have lots of complicated operations yielding strings that need to be concatenated, then you would be better off using a StringBuilder and appending them yourself.

I am not sure about JDK 1.6 (javac is part of JDK) but when I compile it with JDK 1.7, I get an appropriate disassembly.
The compilers are smart. In JDK, I think if you have s = "a" + "b" + "c" it will perhaps do it this way (use StringBuilder instead), but not the other way. More concretely, if all strings are compile-time constants (string literals) it will do even better -- calculate the string literal and replace the concatenation with that, so there will be less overhead at runtime.

Just For Reference
Your questions have already been answered by Oliver Charlesworth but I think you are checking the wrong place to start this question.
You should check the ByteCode using javap -v YouClass.class instead of using the IDE to check the decompiled code which can be quite confusing.
The original java code
public class LockElimination {
private static String concat(String s1, String s2, String s3) {
return s1 + s2 + s3;
}
}
The ByteCode generated by javap -v LockElimination.class
Constant pool:
#1 = Methodref #7.#16 // java/lang/Object."<init>":()V
#2 = Class #17 // java/lang/StringBuilder
#3 = Methodref #2.#16 // java/lang/StringBuilder."<init>":()V
#4 = Methodref #2.#18 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#5 = Methodref #2.#19 // java/lang/StringBuilder.toString:()Ljava/lang/String;

Related

Java converting int variable to String by adding an empty string?

The second argument of the addFormDataPart call should be a string.
int privacyLevel = 0;
builder.addFormDataPart("privacy",privacyLevel);
However, since privacyLevel is an integer, it needs to be converted to String.
In the tutorial, he made the conversion by adding an empty String at the end of privacyLevel:
builder.addFormDataPart("privacy",privacyLevel+"");
I found this to be an unusual way of converting an int to string. And all the research I've done pointed me to traditional methods of conversion.
So does anyone have an explanation for this?
And is this even a "good practice"?
You can also use the proper tool: Integer.toString(int): this might be easier to read as it clearly show your intent on getting a String out of your int.
int privacyLevel = 0;
builder.addFormDataPart("privacy", Integer.toString(privacyLevel));
When you use:
builder.addFormDataPart("privacy", "" + privacyLevel);
You are creating a new String from "" and Integer.toString(privacyLevel), but there might be some optimization during compile time or at runtime:
Compiler can detect the "" and directly use Integer.toString(privacyLevel).
Compiler may replace the + operation by the String::concat method. Said method may return the other String when itself is empty, or return itself when the other String is empty (in openjdk 8u232, the method is actually checking the length of other and always perform a concatenation).
Now, to see what the compiler does, here is a simple code which does nothing extraordinary:
class Foobar {
public static void main(String[] args) {
int n = 1;
String s = n + "";
}
}
If you call javap -p Foobar.class, you can see what the compiler did (with Java 11.0.6, Java 8 use a StringBuilder):
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=3, args_size=1
0: iconst_1
1: istore_1
2: iload_1
3: invokedynamic #2, 0 // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;
8: astore_2
9: return
LineNumberTable:
line 8: 0
line 9: 2
line 10: 9
Using Integer.toString only change the invokedynamic to invokestatic:
3: invokestatic #2 // Method java/lang/Integer.toString:(I)Ljava/lang/String
The compiler does not try to be intelligent in this case and don't optimize "" + int.
If you read Javadoc of java.lang.invoke.StringConcatFactory.makeConcatWithConstants(Lookup, String, MethodType, String, Object...), it references JLS 15.18.1 and JLS 5.1.11.
The JLS 15.18.1 explains the concatenation operation from String + Not a String:
If only one operand expression is of type String, then string
conversion (§5.1.11) is performed on the other operand to produce a
string at run time.
The JLS 5.1.11 explains how to convert an int to String:
A value x of primitive type T is first converted to a reference value
as if by giving it as an argument to an appropriate class instance
creation expression (§15.9):
If T is byte, short, or int, then use new Integer(x).
To answer your question:
I found this to be an unusual way of converting an int to string. And all the research
I've done pointed me to traditional methods of conversion.
So does anyone have an explanation for this? And is this even a "good practice"?
What's unusual in your case if the fact the String is after the number, rather than before (as in "privacyLevel: " + privacyLevel), but that is not strange given the JLS 15.18.1.
I could not say it is a good practice, even though it is relative, but I'd say it is legacy practice born for the fact that Integer.toString is not so old (I can't remember if it was added in Java 5 or 6) and that the easier way was to doing n + "" or "" + n.
I would personally favor Integer.toString because I find n + "" rather ugly. It might also be better in terms of performance due to the complexity of the conversion done otherwise. Luckily for you or my answer, someone did a JMH benchmark.
Last but not least, if you stick with concatenation, the result will depends on the version of compiler which will do the actual transformation:
You are using Android Studio, and what apply to vanilla Java may not completely apply here.
Java 8 use a StringBuilder to generate an int' String.
Java 11 use invokedynamic and a lot of stuff harder (for me) to explain, but I assume it does its job and perform as well, if better, than StringBuilder.
Integer.toString seems to be optimized in newer hotspot JVM (it is annotated #HotSpotIntrinsicCandidate in Java 13).

String concatenation with the + symbol

Today I was reading Antonio's Blog about toString() performance and there is a paragraph:
What used to be considered evil yesterday (“do not concatenate Strings with + !!!“), has become cool and efficient! Today the JVM compiles the + symbol into a string builder (in most cases). So, do not hesitate, use it.
Now I am confused, because he is saying Today the JVM compiles the + symbol into a string builder (in most cases), but I have never heard or seen(code) anything like this before.
Could someone please give example where JVM does this and in what conditions it happens?
The rule
“do not concatenate Strings with + !!!“
is wrong, because it is incomplete and therefore misleading.
The rule is
do not concatenate Strings with + in a loop
and that rule still holds. The original rule was never meant to be applied outside of loops!
A simple loop
String s = "";
for (int i = 0; i < 10000; i++) { s += i; }
System.out.println(s);
is still much still much slower than
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) { sb.append(i); }
System.out.println(sb.toString());
because the Java compiler has to translate the first loop into
String s = "";
for (int i = 0; i < 1000; i++) { s = new StringBuilder(s).append(i).toString(); }
System.out.println(s);
Also the claim
Today the JVM compiles the + symbol into a string builder (in most cases).
is misleading at least, because this translation was already done with Java 1.0 (ok, not with StringBuilder but with StringBuffer, because StringBuilder was only added with Java5).
One could also argue that the claim
Today the JVM compiles the + symbol into a string builder (in most cases).
is simply wrong, because the compilation is not done by the JVM. It is done by the Java Compiler.
For the question: when does the Java compiler use StringBuilder.append() and when does it use some other mechanism?
The source code of the Java compiler (version 1.8) contains two places where String concationation through the + operator is handled.
the first place is String constant folding (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/com/sun/tools/javac/comp/ConstFold.java?av=f#314). In this case the compiler can calculate the resulting string and works with the resulting string.
the second place is where the compiler creates the code for assignment operations (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/com/sun/tools/javac/jvm/Gen.java?av=f#2056). In this case the compiler always emits code to create a StringBuilder
The conclusion is that for the Java compiler from the OpenJDK (which means the compiler distributed by Oracle) the phrase in most cases means always. (Though this could change with Java 9, or it could be that another Java compiler like the one that is included within Eclipse uses some other mechanism).
Holger is right in his comment that in java-9 + for String concatenation is going to change from a StringBuilder to a strategy chosen by the JRE via invokedynamic. There are 6 strategies that are possible for String concatenation in jdk-9:
private enum Strategy {
/**
* Bytecode generator, calling into {#link java.lang.StringBuilder}.
*/
BC_SB,
/**
* Bytecode generator, calling into {#link java.lang.StringBuilder};
* but trying to estimate the required storage.
*/
BC_SB_SIZED,
/**
* Bytecode generator, calling into {#link java.lang.StringBuilder};
* but computing the required storage exactly.
*/
BC_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that in the end calls into {#link java.lang.StringBuilder}.
* This strategy also tries to estimate the required storage.
*/
MH_SB_SIZED,
/**
* MethodHandle-based generator, that in the end calls into {#link java.lang.StringBuilder}.
* This strategy also estimate the required storage exactly.
*/
MH_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that constructs its own byte[] array from
* the arguments. It computes the required storage exactly.
*/
MH_INLINE_SIZED_EXACT
}
And the default one is not using a StringBuilder, it is MH_INLINE_SIZED_EXACT. It is actually pretty crazy how the implementation works, and it is trying to be highly optimized.
So, no the advice there as far as I can tell is bad. That by the way is the main effort that was put into by jdk by Aleksey Shipilev. He also added a big change into String internals in jdk-9 as they are now backed by a byte[] instead of char[]. This needed because ISO_LATIN_1 Strings can be encoded in a single byte (one character - one byte) so a lot of less space.
The statement, in this exact form, is just wrong, and it fits into the picture that the linked blog continues to write nonsense, like that you had to wrap references with Objects.toString(…) to handle null, e.g. "att1='" + Objects.toString(att1) + '\'' instead of just "att1='" + att1 + '\''. There is no need to do that and apparently, the author did never re-check these claims.
The JVM is not responsible for compiling the + operator, as this operator is merely a source code artifact. It’s the compiler, e.g. javac which is responsible, and while there is no guaranty about the compiled form, compilers are encouraged to use a builder by the Java Language Specification:
An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.
Note that even if a compiler does not perform this optimization, there still is no such thing as a + operator on the byte code level, so the compiler has to pick an operation, a JVM understands, e.g. using String.concat, which might be even faster than using a StringBuilder in the case you’re just concatenating exactly two strings.
Even assuming the worst compilation strategy for string concatenation (still being within the specification), it would be wrong to say to never concatenate strings with +, as when you are defining compile time constants, using + is the only choice, and, of course, a compile-time constant is usually more efficient than using a StringBuilder at runtime.
In practice, the + operator applied to non constant strings was compiled to a StringBuffer usage before Java 5 and to a StringBuilder usage in Java 5 to Java 8. When the compiled code is identical to the manual usage of StringBuffer resp. StringBuilder, there can’t be a performance difference.
The transition to Java 5, more than a decade ago, was the first time, where string concatenation via + had a clear win over manual StringBuffer use, as simply recompiling the concatenation code made it use the potentially faster StringBuilder internally, while the code manually dealing with StringBuffer needed to be rewritten to use StringBuilder, which had been introduced in that version.
Likewise, Java 9 is going to compile the string concatenation using an invokedynamic instruction allowing the JRE to bind it to actual code doing the operation, including optimizations not possible in ordinary Java code. So only recompiling the string concatenation code is needed to get this feature, while there is no equivalent manual usage for it.
That said, while the premise is wrong, i.e. string concatenation never was considered evil, the advice is correct, do not hesitate to use it.
There are only a few cases where you really might improve performance by dealing with a buffer manually, i.e. when you need a large initial capacity or concatenate a lot within loops and that code has been identified as an actual performance bottleneck by a profiling tool…
When you concatenate strings using + operator, compiler translates concatenation code to use StringBuffer for better performance. In order to improve performance StringBuffer is the better choice.
The quickest way of concatenate two string using + operator.
String str = "Java";
str = str + "Tutorial";
The compiler translates this code as:
String s1 = "Java";
StringBuffer sb = new StringBuffer(s1);
sb.append("Tutorial");
s1 = sb.toString();
So it is better to use StringBuffer OR String.format for concatenation
Using String.format
String s = String.format("%s %s", "Java", "Tutorial");

What is the difference when concatenating a String as a variable with a Character vs concatenating with an other String?

When i see something (pseudo 1-liner) like this:
str1 + "a" + str2
Is it much worse (or better/equal) than the following (pseudo 1-liner)?
str1 + 'a' + str2
Update: Better example (by #QPaysTaxes) to reduce confusion regarding my original example.
What i tried:
Various stuff for the past 10 years programming Java but i never managed to realy see whats under the hood - e.g. i would assume the second is slightly "faster/better" because there is no String-Object(s) created for the slash-sign and/or the garbage collector of Java has to handle less.
I once prepared for the Java Certificates and might would have been able to argue better back in that time but it seems even thus its my daily business the "theory" about Java must be keept up to date as well... I know without any better explanation than my assumptation that indexOf('c') should be used rather than indexOf("C") and i wondered if the same counts for String-concatenation.
I also googled a bit but as my title might imply i am not quite good to describe what i am looking for without a example. I am sorry for this and the possibility this handicap just produced a duplicate.
What i will try:
Based on the accepted answer here String concatenation: concat() vs "+" operator i hope to be able to have a start to see whats under the hood and one day be able to argue/ answer such questions that profund.
Based on the accepted answer here I hope to be able to have a start to
see whats under the hood.
Let's have a look at the generated bytecode when concatenating a String with a Character:
String str1 = "a" + "test";
String str2 = 'a' + "test";
0: ldc #2 // String atest
2: astore_1
3: ldc #2 // String atest
5: astore_2
as you can see, there is no difference, the compiler will convert it to the same bytecode.
Now let's have a look at the generated bytecode when concatenating a Character to a String variable.
String str1 = "a" + str3; //str3 is a String
String str2 = 'a' + str3;
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: ldc #5 // String a
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_1
16: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_2
23: new #3 // class java/lang/StringBuilder
26: dup
27: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
30: bipush 97
32: invokevirtual #8 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
35: aload_1
36: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
39: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
As you can see, there is a little difference.
10: ldc #5 // String a
ldc push a constant #index from a constant pool (String, int or float) onto the stack.
Therefore, if you are concatenating directly with a variable, concatenating a Character will generate less bytecode, that is what is under the hood.
Now for the performance issue, this wont represent any signifiant performance difference as the JIT compiler optimize most of the temporary objects, unless you specified when running your program to disable the JIT compiler using -Djava.compiler=NONE.
I prefer to use "a" instead of 'a' to make sure the result is a String.
Consider this:
public static void main(String... args) {
String s = "foo";
int i = 1;
Object arg = s + '/' + i;
log(arg);
}
private static void log(Object... args) {
MessageFormat format = new MessageFormat("bar {0}");
String message = format.format(args);
System.out.println(message); // or write to a log or something
}
Assume you decide you don’t need s in the message anymore and change the third line in the main method to:
Object arg = '/' + i;
Then arg will contain just a number, because char + int does not concatenate, but add the values.
If you construct a filename you sure will use it afterwards. That in most cases involves access to a physical media which is magnitudes slower than anything you can do wrong with concatenating your Strings. So, do what is maintable and don't worry about performance in this particular case.
My advice when building filenames is to use the File class or Path that will automatically make sure to get path separators right.
EDIT: As you point out in your comment, your question is about the general case. Just look at the source. StringBuilder.append(String) ends up doing a System.arraycopy() in String.getChars() whilst StringBuilder.append(char) directly copies a single character. So in theory, StringBuilder.append(char) will be faster.
However, you'd have to benchmark this to see if it makes any difference in practice.
I'm not sure if either of the options is better in terms of performance, but I can think of another issue to consider, that would prefer the first snippet.
The compiler can better protect you against typos if you append primitives instead of the String representation of those primitives.
Consider:
String plus10 = "plus" + 10;
If you type by mistake
String plus10 = "plus" + 1O;
The compiler will give you an error.
If, on the other hand, you type
String plus10 = "plus" + "1O";
The compiler will have no problem with that.
The same goes for appending chars
String plus = "x" + '++' + "y";
will not compile while
String plus = "x" + "++" + "y";
will pass compilation.
Of course it would be better to use constants and not hard coded values (and to append to a StringBuilder instead of using String concatenation), but even for the constants I would prefer primitive types over Strings, as they give you one more level of protection against errors.
Looking at the source code often helps to understand what is happening.
String s = s1 + s2
Will execute:
String s = new StringBuilder(s1).append(s2).toString();
Now look into the source code for append(char) and append(string) of the class StringBuilder:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/AbstractStringBuilder.java#AbstractStringBuilder.append%28char%29
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/AbstractStringBuilder.java#AbstractStringBuilder.append%28java.lang.String%29
You will see that append(string) performs more checks to see if the string is null or empty. However, you probably will not notice any difference.
There is no any significant difference in performance actually. An average it will take the same time to do string concatenation.
However, internally Java compiler replaces + operator with StringBuilder at compile time.
So when using + operator with char, compiler will convert it into a StringBuilder internally and use .append(char). The same will happen with a string, with a difference that it will use .append(String).
And as I mentioned above, there is no difference an average. Simple test will show that time difference is close to 0. So this is really matter of readability. And from readability perspective, if you are concentrating strings, it's better to keep the type same, and use String even for single characters, rather than char
This is what's under the hood: String str = s1 + "/"; essentially creates 2 new separate String objects (str and new String("/")).
This is no problem for small software, but think about it memory-wise if you were to create 2 String objects (keep in mind: objects reserve 1 entry in the Stack plus contents kept in the Heap) for n > 500.000 database entries.
Using single quotes, like String str = s1 + '/', will result in another process entirely. '/' stands for the numeric ASCii character representation value of whatever single character is written between the quotes. This operation has a constant (O(1)) runtime (think instant array access) and will naturally be faster than creating and referencing objects.
As lots of people have suggested already, using a StringBuilder object for String concatenation is much easier on memory than building strings with the + operator.

String concatenation with operator + vs using stringbuffer?

Is there any difference b/w 1 and 2 in terms of concatenation if i do it instance method. I mean in either case only one object will be constructed ultimately i.e "abc" .Yes only difference i see is test will lie inside permgen space even thread come out of instance method but x will be garbage collected once thread is out of method but in terms of number of objects constructred will be same. Right?
// option 1
String test="a"+"b"+"c";
// option 2
StringBuffer x = new StringBuffer().append("a").append("b").append("c").toString()
I referred the link http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuffer.html to reach this conclusion.
First notice that the documentation you have linked is very old. Notice it's for Java 1.4.2.
J2SE 1.4.2 is in its Java Technology End of Life (EOL) transition period. The EOL transition period began Dec, 11 2006 and will complete October 30th, 2008, when J2SE 1.4.2 will have reached its End of Service Life (EOSL).
In newer versions of the documentation this statement has been removed. However another statement has been added that you should be aware of:
As of release JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread, StringBuilder. The StringBuilder class should generally be used in preference to this one, as it supports all of the same operations but it is faster, as it performs no synchronization.
Secondly notice that the documentation you refer to has this code:
x = "a" + 4 + "c";
The 4 there isn't just a typo. Your example is different because the compiler will convert the code to use just a single string literal. These two lines are the same:
x = "a" + "b" + "c";
x = "abc";
The string literal will be interned.
But in the general case where the compiler cannot just use a single string literal, the compiler will transform the first version into the second, except it will use StringBuilder instead because it is more efficient.
First of all - use StringBuilder instead of StringBuffer, StringBuffer is deprecated now.
And for your question, nowadays it doesn't really matter, compiler automacally transforms String concacenation to StringBuilder.
There are only two cases where to use it. First one is better code readability (for example if you are building long Strings like SQL queries). And second one, when you concanete Strings in the loop, compiler for always make a new StringBuilder instance for each walk through loop, so be carefull about that.
First of all, StringBuilder is to StringBuffer what ArrayList is to Vector: it should be preferred because it's not synchronized.
Your first String is entirely constructed at compilation time, and is stored as a String literal. This literal is interned inside a pool, and the test variable always points to the same String instance.
Your second snippet dynamically concatenates, at runtime, three String literals. It returns a new String instance each time it's called.
Looking at the bytecode generated by the 2 examples, the first string is transformed into the "abc" string literal, whereas the second calls StringBuilder methods. You can actually test it with System.out.println(test == "abc");, which prints true.
0: ldc #2 // String abc
2: astore_1
3: new #3 // class java/lang/StringBuffer
6: dup
7: invokespecial #4 // Method java/lang/StringBuffer."<init>":()V
10: ldc #5 // String a
12: invokevirtual #6 // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
15: ldc #7 // String b
17: invokevirtual #6 // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
20: ldc #8 // String c
22: invokevirtual #6 // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
25: invokevirtual #9 // Method java/lang/StringBuffer.toString:()Ljava/lang/String;
28: astore_2
In this specific case, where you're concatenating three string literals at compile time, the compiler will generate code just as if you'd typed:
String test="abc";
thus avoiding any intermediate objects altogether.
I think in case of memory usages both are same.

append or + operator in StringBuffer?

In my project there are some code snippets which uses StringBuffer objects, and the small part of it is as follows
StringBuffer str = new StringBuffer();
str.append("new " + "String()");
so i was confused with the use of append method and the + operator.
ie the following code could be written as
str.append("new ").append("String()");
So are the two lines above same?(functionally yes but) Or is there any particular usage of them? ie performance or readability or ???
thanks.
In that case it's more efficient to use the first form - because the compiler will convert it to:
StringBuffer str = new StringBuffer();
str.append("new String()");
because it concatenates constants.
A few more general points though:
If either of those expressions wasn't a constant, you'd be better off (performance-wise) with the two calls to append, to avoid creating an intermediate string for no reason
If you're using a recent version of Java, StringBuilder is generally preferred
If you're immediately going to append a string (and you know what it is at construction time), you can pass it to the constructor
Actually the bytecode compiler will replace all string concatenation which involve non constants in a Java program with invocations of StringBuffer. That is
int userCount = 2;
System.out.println("You are the " + userCount + " user");
will be rewritten as
int userCount = 2;
System.out.println(new StringBuffer().append("You are the ").append(userCount).append(" user").toString());
That is at least what is observable when decompiling java class files compiled with JDK 5 or 6. See this post.
The second form is most efficient in terms of performance because there is only one string object that is created and is appended to the stringbuffer.
The first form creates three string objects 1) for "new" 2)for "new String" 3) for the concatenated result of 1) and 2). and this third string object is concatenated to the string buffer.
Unless you are working with concurrent systems, use StringBuilder instead of StringBuffer. Its faster but not thread-safe :)
It also shares the same API so its more or less a straight find/replace-

Categories