StringBuffer or HashMap
Which is the best way to append codes and also makes performance better.
StringBuffer sql = new StringBuffer();
DBDatabase db = UTIL.getDatabase();
sql.append("SELECT I.FLDCODE, I.FLDDESCR, I.FLDWORKPHON FROM ");
sql.append(db.getSchema());
sql.append("TRNINSTR I, ");
sql.append(db.getSchema());
sql.append("TRNCRSIN C WHERE C.FLDCOURSE = ? AND C.FLDINSTRUCT = I.FLDCODE AND (I.FLDINACTIVE IS NULL OR I.FLDINACTIVE <> 'y') ORDER BY C.FLDSEQUENCE");
DBPreparedStatement stmt = new DBPreparedStatement(db, sql, "TrainPage.getInfoInstrList");
stmt.setString(1, courseType);
DBResultSet rs = stmt.executeQuery();
stmt.close();
StringBuilder performs even better. Bear in mind that the slow part is database access not statement preparation.
Your question is unclear ("appending codes"? "HashMap"?), but I'll assume that you are asking what is the more efficient way to build a String.
In general, a StringBuilder is more efficient than a StringBuffer, because the latter's methods are synchronized and this is just an unnecessary overhead for a thread-confined object.
But then there is the question of whether using a StringBuilder is more efficient than simple String concatenation. And the answer to that is that "it depends".
If you are doing lots of separate concatenations, then a StringBuilder is typically faster; e.g.
String s = "";
for (int i = 0; i < 1000; i++) {
s += "X";
}
If you are doing all of the concatenations in one expression, then it probably makes no difference:
String s = "Hi " + name + ". It is a might fine " + day + ".";
This is because the Java compiler will turn that into code that creates a StringBuilder and performs a series of append calls.
However, that is a slight over-simplification. On the one hand, if your application can easily calculate the length of the final String, you can get somewhat better performance using a StringBuilder by allocating the builder with the right initial capacity. On the other hand, the compiler will evaluate concatenations of String literals before hand, so
String s = "Hi " + "mom" + ". is a might fine " + "tuesday" + ".";
will be faster than:
StringBuilder sb = new StringBuilder();
sb.append("Hi ");
sb.append("mom");
sb.append(". is a might fine ");
sb.append("tuesday");
sb.append(".");
String s = sb.toString();
But the bottom line is that it probably doesn't matter. Unless you do a huge amount of string building, the chances are that the impact on the overall performance of your application will be minimal.
Related
On Java 1.7+ should we still need to convert "this string" + "should" + "be" + "joined" using StringBuffer.append for best practices?
1) constant expressions (JLS 15.28) like "this string" + " should" + " be" + " joined" do not need StringBuilder because it is calculated at compile time into one string "this string should be joined"
2) for non-constant expressions compiler will apply StringBuilder automatically. That is, "string" + var is equivalent to new StringBuilder().append("string").append(var).toString();
We only need to use StringBuilder explicitly where a string is constructed dynamically, like here
StringBuilder s = new StringBuilder();
for (String e : arr) {
s.append(e);
}
// using String concatentation
String str = "this string" + "should" + "be" + "joined";
// using StringBuilder
StringBuilder builder = new StringBuilder();
builder.append("this string");
builder.append("should");
builder.append("be");
builder.append("joined");
String str = builder.toString();
Your decision to use raw String concatenation versus StringBuilder is probably going to depend on the readability and maintainability of your code, rather than performance. Under the Oracle JVM, using direct String concatenation, the compiler will actually use a single StringBuilder under the hood. As a result, both examples I gave above would have nearly identical bytecode. If you find yourself doing many series of raw String concatenations, then StringBuilder may offer you a performance improvement. See this article for more information (which was written after Java 7 was released).
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
Strings are immutable. Stringbuilders are not, so you can append characters at the end. Strings are character arrays if i am not wrong, than why do we use character arrays separately and Strings separately, Do we really need to use character arrays?
Secondly, there are character arrays and then there are Arraylists. Array lists holds complete objects? I am a bit confused actually.
String cat = "c" + "a" + "t";
cat = cat + cat;
StringBuilder sb = new StringBuilder();
sb.append(city);
sb.append(", ");
sb.append(state);
sb.toString();
Char apple[5]={'a','p','p','l','e'};
Arraylist<MyCar>obj = new Arraylist<MyCar>();
Which should be used where?
This Explain the best: between string and stringBuilder
Ref:Correct way to use StringBuilder
Note that the aim (usually) is to reduce memory churn rather than total memory used, to make life a bit easier on the garbage collector.
Will that take memory equal to using String like below?
No, it'll cause more memory churn than just the straight concat you quoted. (Until/unless the JVM optimizer sees that the explicit StringBuilder in the code is unnecessary and optimizes it out, if it can.)
If the author of that code wants to use StringBuilder (there are arguments for, but also against; see note at the end of this answer), better to do it properly (here I'm assuming there aren't actually quotes around id2 and table):
StringBuilder sb = new StringBuilder(some_appropriate_size);
sb.append("select id1, ");
sb.append(id2);
sb.append(" from ");
sb.append(table);
return sb.toString();
Note that I've listed some_appropriate_size in the StringBuilder constructor, so that it starts out with enough capacity for the full content we're going to append. The default size used if you don't specify one is 16 characters, which is usually too small and results in the StringBuilder having to do reallocations to make itself bigger (IIRC, in the Sun/Oracle JDK, it doubles itself [or more, if it knows it needs more to satisfy a specific append] each time it runs out of room).
You may have heard that string concatenation will use a StringBuilder under the covers if compiled with the Sun/Oracle compiler. This is true, it will use one StringBuilder for the overall expression. But it will use the default constructor, which means in the majority of cases, it will have to do a reallocation. It's easier to read, though. Note that this is not true of a series of concatenations. So for instance, this uses one StringBuilder:
return "prefix " + variable1 + " middle " + variable2 + " end";
It roughly translates to:
StringBuilder tmp = new StringBuilder(); // Using default 16 character size
tmp.append("prefix ");
tmp.append(variable1);
tmp.append(" middle ");
tmp.append(variable2);
tmp.append(" end");
return tmp.toString();
So that's okay, although the default constructor and subsequent reallocation(s) isn't ideal, the odds are it's good enough — and the concatenation is a lot more readable.
But that's only for a single expression. Multiple StringBuilders are used for this:
String s;
s = "prefix ";
s += variable1;
s += " middle ";
s += variable2;
s += " end";
return s;
That ends up becoming something like this:
String s;
StringBuilder tmp;
s = "prefix ";
tmp = new StringBuilder();
tmp.append(s);
tmp.append(variable1);
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(" middle ");
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(variable2);
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(" end");
s = tmp.toString();
return s;
...which is pretty ugly.
It's important to remember, though, that in all but a very few cases it doesn't matter and going with readability (which enhances maintainability) is preferred barring a specific performance issue.
Normally String is used for normal string based requirement, and when a String can suffice it.
String Builder is used whenever you want to manipulate and play with the string.
Character Array is used when you want to easily iterate over each and every character
ArrayList is a collection. Use it for holding object of a particular type.
String is immutable object that includes underlying char array.
In your line 2 you discard your String that you created in line 1 and create a new String.
String builder avoids creating new String objects for every separate substring.
Both arrays and Arraylist can contain objects, the main difference is that Arraylist can grow, arrays can not. The second difference is that Arraylist is really a List...
A String uses a char[]. A String is not a char[], in the same way that an ArrayList<String> is not a String[].
ArrayList type is a dynamic data structure. This means that it can grow depending on need. Array is static, meaning it's dimensions do not change over its lifetime.
This question already has answers here:
String concatenation: concat() vs "+" operator
(12 answers)
Closed 8 years ago.
For string concatenation we can use either the concat() or concat operator (+).
I have tried the following performance test and found concat() is faster and a memory efficient way for string concatenation.
String concatenation comparison for 100,000 times:
String str = null;
//------------Using Concatenation operator-------------
long time1 = System.currentTimeMillis();
long freeMemory1 = Runtime.getRuntime().freeMemory();
for(int i=0; i<100000; i++){
str = "Hi";
str = str+" Bye";
}
long time2 = System.currentTimeMillis();
long freeMemory2 = Runtime.getRuntime().freeMemory();
long timetaken1 = time2-time1;
long memoryTaken1 = freeMemory1 - freeMemory2;
System.out.println("Concat operator :" + "Time taken =" + timetaken1 +
" Memory Consumed =" + memoryTaken1);
//------------Using Concat method-------------
long time3 = System.currentTimeMillis();
long freeMemory3 = Runtime.getRuntime().freeMemory();
for(int j=0; j<100000; j++){
str = "Hi";
str = str.concat(" Bye");
}
long time4 = System.currentTimeMillis();
long freeMemory4 = Runtime.getRuntime().freeMemory();
long timetaken2 = time4-time3;
long memoryTaken2 = freeMemory3 - freeMemory4;
System.out.println("Concat method :" + "Time taken =" + timetaken2 +
" Memory Consumed =" + memoryTaken2);
Result
Concat operator: Time taken = 31; Memory Consumed = 2259096
Concat method : Time taken = 16; Memory Consumed = 299592
If concat() is faster than the operator then when should we use concatenation operator (+)?
The concat method always produces a new String with the result of concatenation.
The plus operator is backed by StringBuilder creation, appending all String values you need and further toString() calling on it.
So, if you need to concatenate two values, concat() will be better choice. If you need to concatenate 100 values, you should use the plus operator or explicitly use StringBuilder (e.g. in case of appending in a cycle).
In fact s1 + s2 and s1.concat(s2) are very different.
s1 + s2 is converted by javac into
(new StringBuilder(String.valueOf(s1)).append(s2).toString();
You can see it if you decompile .class. This construct is not very efficient; it involves up to three new char[] allocations and three char[] copy operations.
s1.concat(s2) is always one new char[] + one copy operation, see String.java
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
char buf[] = new char[count + otherLen];
getChars(0, count, buf, 0);
str.getChars(0, otherLen, buf, count);
return new String(0, count + otherLen, buf);
}
Note that new String(int, int, char[]) is String's package private constructor. It uses char buf[] directly, without the usual copying to ensure the buf invisibility for the String immutability.
Your test needs to be running for at least 2 seconds with each loop in a separate method to be meaningful. Short tests can be every difficult to reproduce and compare. From your timing it appears you are using Windows (i.e. because you times are 16 and 31 ms ;) Try System.nanoTime() instead. When your loop iterates over 10,000 times the whole method is compiled. This means your later method is already compiled when it is started.
In answer to your question concat is marginally faster when adding two Strings. However, it comes with a typing and conceptual overhead which is likely to be much greater than the CPU you save. Even based on your tests repeating 100,000 times it saves less than 15 ms, and yet it cost you far, far more than that in your time (which is likely to be worth more) You could find in a future version of the JVM, the difference is optimised always and the complexity of your code is still there.
EDIT: I didn't notice that the memory result was suspect.
String str = null;
//------------Using Concatenation operator-------------
long time1 = System.currentTimeMillis();
long freeMemory1 = Runtime.getRuntime().freeMemory();
for (int i = 0; i < 10000; i++) {
str = "Hi";
str = str + " Bye";
}
long time2 = System.currentTimeMillis();
long freeMemory2 = Runtime.getRuntime().freeMemory();
long timetaken1 = time2 - time1;
long memoryTaken1 = freeMemory1 - freeMemory2;
System.out.println("Concat operator :" + "Time taken =" + timetaken1 + " Memory Consumed= " + memoryTaken1);
str = null;
//------------Using Concat method-------------
long time3 = System.currentTimeMillis();
long freeMemory3 = Runtime.getRuntime().freeMemory();
for (int j = 0; j < 10000; j++) {
str = "Hi";
str = str.concat(" Bye");
}
long time4 = System.currentTimeMillis();
long freeMemory4 = Runtime.getRuntime().freeMemory();
long timetaken2 = time4 - time3;
long memoryTaken2 = freeMemory3 - freeMemory4;
System.out.println("Concat method :" + "Time taken =" + timetaken2 + " Memory Consumed= " + memoryTaken2);
prints when run with -XX:-UseTLAB -mx1g
Concat operator :Time taken =12 Memory Consumed= 1291456
Concat method :Time taken =7 Memory Consumed= 560000
making the ratio of memory usage about 2:1. In the original question the result vary every time you run it, sometimes the .concat() appears to use more.
I believe the 'style' of concatenation is going to make a difference.
For concat(), it internally creates a new char array buffer, and returns a new string based on that char array.
For the + operator, the compiler in fact translate it to use StringBuffer/StringBuilder.
Therefore, if you are concatenating two strings, concat() is definitely a better choice because the number of objects created is only the result String (and the char buffer used inside), while using the + operator will be translated to:
result = strA + strB;
-- translate to -->
result = new StringBuilder(strA).append(strB).toString();
An extra StringBuilder instance is created.
However, if you are concatenating, for example five strings in a row, each concat() will create a new String object. While using the + operator, the compiler will translate the statement to one StringBuilder with multiple append operations. It is definitely saving a lot of unnecessary temporary object instance:
result = strA + strB + strC + strD + strE;
-- translate to -->
result = new StringBuilder(strA).append(strB).append(strC).append(strD).append(strE).toString();
You can always use + if only you use >= Java 1.5 and you don't declare your base String (that you want concatenate) outside of the loop. In Java 1.5 it results in creating new StringBuilder and working on it till your string is complete. That's the fastest way.
Anyway - if you are in a loop (and concatenating strings with +) - every iteration of the loop creates a new StringBuilder - that's not the best idea. So this is where you should force the use of StringBuilder or StringBuffer (thread safe) classes.
Generally, this link clearly answers your question, and gives you complete knowledge:
http://littletutorials.com/2008/07/16/stringbuffer-vs-stringbuilder-performance-comparison/
Though both the operator and the method are giving the same output, the way they work internally differs.
The concat() method that just concatenates str1 with str2 and outputs a string, is more efficient for a small number of concatenations.
But with concatenation operator '+', str1+=str2; will be interpreted as
str1 = new StringBuilder().append(str1).append(str2).toString();
You can use the concat method when using a fewer number of strings to concatenate. But the StringBuilder method would be fast in terms of performance, if you are using a large number of strings.
Actually, both are the same. If you see the code of concat(String paramString) it will return a new object of string, and in the (+) operator it it will also generate a new string object.
If you don't want to create a new object then use string builder to concatenate two strings.
In general it is a bad practice to concatenate Strings with + and with concat(). If you want to create a String use StringBuilder instead.
I have code as follows :
String s = "";
for (My my : myList) {
s += my.getX();
}
Findbugs always reports error when I do this.
I would use + if you are manually concatenating,
String word = "Hello";
word += " World!";
However, if you are iterating and concatenating I would suggest StringBuilder,
StringBuilder sb = new StringBuilder();
for (My my : myList) {
sb.append(my.getX());
}
The String object is immutable in Java. Each + means another object. You could use StringBuffer to minimize the amount of created objects.
Each time you do string+=string, it calls method like this:
private String(String s1, String s2) {
if (s1 == null) {
s1 = "null";
}
if (s2 == null) {
s2 = "null";
}
count = s1.count + s2.count;
value = new char[count];
offset = 0;
System.arraycopy(s1.value, s1.offset, value, 0, s1.count);
System.arraycopy(s2.value, s2.offset, value, s1.count, s2.count);
}
In case of StringBuilder, it comes to:
final void append0(String string) {
if (string == null) {
appendNull();
return;
}
int adding = string.length();
int newSize = count + adding;
if (newSize > value.length) {
enlargeBuffer(newSize);
}
string.getChars(0, adding, value, count);
count = newSize;
}
As you can clearly conclude, string + string creates a lot of overhead, and in my opinion should be avoided if possible. If you think using StringBuilder is bulky or to long you can just make a method and use it indirectly, like:
public static String scat(String... vargs) {
StringBuilder sb = new StringBuilder();
for (String str : vargs)
sb.append(str);
return sb.toString();
}
And use it like:
String abcd = scat("a","b","c","d");
In C# I'm told its about as same as string.Concat();. In your case it would be wise to write overload for scat, like:
public static String scat(Collection<?> vargs) {
StringBuilder sb = new StringBuilder();
for (Object str : vargs)
sb.append(str);
return sb.toString();
}
Then you can call it with:
result = scat(myList)
The compiler can optimize some thing such as
"foo"+"bar"
To
StringBuilder s1=new StringBuilder();
s1.append("foo").append("bar");
However this is still suboptimal since it starts with a default size of 16. As with many things though you should find your biggest bottle necks and work your way down the list. It doesn't hurt to be in the habbit of using a SB pattern from the get go though, especially if you're able to calculate an optimal initialization size.
Premature optimization can be bad as well as it often reduces readability and is usually completely unnecessary. Use + if it is more readable unless you actually have an overriding concern.
It is not 'always bad' to use "+". Using StringBuffer everywhere can make code really bulky.
If someone put a lot of "+" in the middle of an intensive, time-critical loop, I'd be annoyed. If someone put a lot of "+" in a rarely-used piece of code I would not care.
I would say use plus in the following:
String c = "a" + "b"
And use StringBuilder class everywhere else.
As already mentioned in the first case it will be optimized by the compiler and it's more readable.
One of the reasons why FindBugs should argue about using concatenation operator (be it "+" or "+=") is localizability. In the example you gave it is not so apparent, but in case of the following code it is:
String result = "Scanning found " + Integer.toString(numberOfViruses) + " viruses";
If this looks somewhat familiar, you need to change your coding style. The problem is, it will sound great in English, but it could be a nightmare for translators. That's just because you cannot guarantee that order of the sentence will still be the same after translation – some languages will be translated to "1 blah blah", some to "blah blah 3". In such cases you should always use MessageFormat.format() to build compound sentences and using concatenation operator is clearly internationalization bug.
BTW. I put another i18n defect here, could you spot it?
The running time of concatenation of two strings is proportional to the length of the strings. If it is used in a loop running time is always increasing. So if concatenation is needed in a loop its better to use StringBuilder like Anthony suggested.
I read a lot about using StringBuffer and String especially where concatenation is concerned in Java and whether one is thread safe or not.
So, in various Java methods, which should be used?
For example, in a PreparedStatement, should query be a StringBuffer:
String query = ("SELECT * " +
"FROM User " +
"WHERE userName = ?;");
try {
ps = connection.prepareStatement(query);
And then again, in a String utility methods like:
public static String prefixApostrophesWithBackslash(String stringIn) {
String stringOut = stringIn.replaceAll("'", "\\\\'");
return stringOut;
}
And:
// Removes a char from a String.
public static String removeChar(String stringIn, char c) {
String stringOut = ("");
for (int i = 0; i < stringIn.length(); i++) {
if (stringIn.charAt(i) != c) {
stringOut += stringIn.charAt(i);
}
}
return stringOut;
}
Should I be using StringBuffers? Especially where repalceAll is not available for such objects anyway.
Thanks
Mr Morgan.
Thanks for all the advice. StringBuffers have been replaced with StringBuilders and Strings replaced with StringBuilders where I've thought it best.
You almost never need to use StringBuffer.
Instead of StringBuffer you probably mean StringBuilder. A StringBuffer is like a StringBuilder except that it also offers thread safety. This thread safety is rarely needed in practice and will just cause your code to run more slowly.
Your question doesn't seem to be about String vs StringBuffer, but about using built-in methods or implementing the code yourself. If there is a built-in method that does exactly what you want, you should probably use it. The chances are it is much better optimized than the code you would write.
There is no simple answer (apart from repeating the mantra of StringBuilder versus StringBuffer ... ). You really have understand a fair bit about what goes on "under the hood" in order to pick the most efficient solution.
In your first example, String is the way to go. The Java compiler can generate pretty much optimal code (using a StringBuilder if necessary) for any expression consisting of a sequence of String concatenations. And, if the strings that are concatenated are all constants or literals, the compiler can actually do the concatenation at compile time.
In your second example, it is not entirely clear whether String or StringBuilder would be better ... or whether they would be roughly equivalent. One would need to look at the code of the java.util.regex.Matcher class to figure this out.
EDIT - I looked at the code, and actually it makes little difference whether you use a String or StringBuilder as the source. Internally the Matcher.replaceAll method creates a new StringBuilder and fills it by appending chunks from the source String and the replacement String.
In your third example, a StringBuilder would clearly be best. A current generation Java compiler is not able to optimize the code (as written) to avoid creating a new String as each character is added.
For the below segment of code
// Removes a char from a String.
public static String removeChar(String stringIn, char c) {
String stringOut = ("");
for (int i = 0; i < stringIn.length(); i++) {
if (stringIn.charAt(i) != c) {
stringOut += stringIn.charAt(i);
}
}
return stringOut;
}
You could just do stringIn.replaceAll(c+"","")
Even in MT code, it's unusual to have multiple threads append stuff to a string. StringBuilder is almost always preferred to StringBuffer.
Modern compilers optimize the code already. So some String additions will be optimized to use StringBuilder and we can keep the String additions if we think, it increases readibility.
Example 1:
String query = ("SELECT * " +
"FROM User " +
"WHERE userName = ?;");
will be optimized to somthing like:
StringBuiler sb = new StringBuilder();
sb.append("SELECT * ");
sb.append("FROM User ");
sb.append("WHERE userName = ?;");
String query = sb.toString();
Example 2:
String numbers = "";
for (int i = 0;i < 20; i++)
numbers = numbers + i;
This can't be optimized and we should use a StringBuilder in code.
I made this observation for SUN jdk1.5+. So for older Java versions or different jdks it can be different. There it could be save to always code StringBuilder (or StringBuffer for jdk 1.4.2 and older).
For cases which can be considered single threaded, the best would be StringBuilder. It does not add any synchronization overhead, while StringBuffer does.
String concatenation by '+' operator is "good" only when you're lazy to use StringBuilder or just want to keep the code easily readable and it is acceptable from performance point of view, like in startup log message "LOG.info("Starting instance " + inst_id + " of " + app_name);"