Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I have a multithreaded Http server in Java 8
which gets thousands of requests per second and has to create responses which require String concatenation. What is the best (fastest) solution to this problem?
I know that in general StringBuilder has much better performance than + operator and I thought StringBuilder will be the best solution but in this case I would have to initialize new StringBuilder for each request.
Moreover, in my problem concatenation always require 3 strings - two of them are final and the middle one is a variable. The variable can take values from the set of ~20 different elements. So the number of possible concatenated strings equals 20 x number_of_different_strings which is about 2000.
Is it better to use StringBuilder or just concatenate Strings (the number will not exceed 2k different strings) or maybe its better to store all created Strings (about 2k) in map and ask for specific one each time?
I know that in general StringBuilder has much better performance than + operator
That is not exactly true. In fact, when you use the + operator, the Java compiler will convert that into using StringBuilder in the compiled code.
The issue is the following. Look at the following code:
String[] names = {"Joe", "Susan", "Fred", "Mary"};
String result = "";
for (String name : names) {
result = result + name;
}
Every time you use the + operator, the Java compiler will create a StringBuilder to perform that operation. The compiler converts the above into something like this:
for (String name : names) {
StringBuilder sb = new StringBuilder(result);
sb.append(name);
result = sb.toString();
}
Note that this is very inefficient code. In each iteration of the loop, a new StringBuilder object is created. The data contained in the string result is copied into that StringBuilder. Then the next name is appended to it, and then the data in the StringBuilder is copied into a new String which is assigned to result. There is a lot of unnecessary copying going on.
You can write much more efficient code by using StringBuilder directly:
StringBuilder sb = new StringBuilder();
for (String name : names) {
sb.append(name);
}
String result = sb.toString();
This way, only one StringBuilder object is created and data is not being copied into it and into a String in each iteration in the loop.
If your code does not involve appending many strings in a loop, and you just have to concatenate three strings, then it does not matter if you use + or a StringBuilder explicitly. In fact, the code written with + would be compiled into exactly the same as what you would write when you would use StringBuilder manually.
Related
I want to optimizes ObjectMapper for a list. The requirement is that I need to add a delimiter after each element of the list. My current code looks like :
StringBuilder strBuilder = new StringBuilder();
for (Event event : segregatedList) {
String eventJson = mapper.writeValueAsString(event);
strBuilder.append("\n");
strBuilder.append(eventJson);
}
This take a huge amount of time for a long list (~10000 events) .How can I optimize the code to do serializes the list in a single go ?
mapper instances are thread-safe, so you can split the mapper.writeValueAsString to a parallel job. I guess something like this may help if you don't worry of the order in which they are appended!
segregatedList.parallelStream().map(event -> mapper.writeValueAsString(event)).collect(Collectors.joining("\n")))
Otherwise, I can see very minimum scope of improving here. Maybe you can optimize json by ignoring properties as mentioned by Dark Knight
There are multiple ways to concatenate Strings in java.
concat() method from java.lang.String
Using + operator
Using StringBuffer
Using StringBuilder
From my personal analysis i can say + call on String gets translated into new StringBuilder().append( "" ). Since StringBuilder(String) constructor allocates a buffer with 16 char, appending more than 16 characters will require buffer reallocation. At last, StringBuffer.toString() calls create a new String object with a copy of StringBuilder buffer.
So if you don't want synchronization overhead StringBuilder stands best among others else i would advice you to use StringBuffer here. I see you are using StringBuilder already, so there is very little scope for improvement here. However you can optimize generated json by ignoring properties which are not useful.
This question already has answers here:
StringBuilder vs String concatenation in toString() in Java
(20 answers)
How Java do the string concatenation using "+"?
(6 answers)
Closed 8 years ago.
I have worked with String, StringBuilder and StringBuffer in java.
I thought of this question, while I was thinking from efficiency point of view.
Does "+" use in String concatenation affect efficiency?
Yes, but so little it shouldn't matter most of the time.
Using '+' for string constants is the most efficient as the compiler can perform the concatenation.
If you are joining two Strings, the concat method is the most efficient as it avoids using a StringBuilder.
There is almost never a good reason to use StringBuffer except for backward compatibility. StringBuilder or StringWriter are a better choice. However, it is still used explicitly more often than StringBuilder in the JDK :P
StringBuffer is dead, long live StringBuffer
If you're concatenating in a single statement, then it won't matter since the compiler/JIT compiler will automatically optimize it using a StringBuilder.
So "a"+b+"c" will be optimized to (new StringBuilder("a").append(b).append("c")).toString()
However, if you're concatenating a large number of Strings in a loop, definitely explicitly use a StringBuilder as it will significantly speed up your program.
String a = "";
for( int i = 0; i < 1000000; i++ )
a += i;
should be changed to
StringBuilder sb = new StringBuilder();
for( int i = 0; i < 1000000; i++ )
sb.append(i);
String a = sb.toString();
A bit of Yes, But still NO
From the JLS, 15.18.1.2
Optimization of String Concatenation
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.
For primitive types, an implementation may also optimize away the creation of a wrapper object by converting directly from a primitive type to a string.
In your example:
" Does +" + " use in String concatenation affect efficiency? "
we have to literal Strings, which might be replaced by the compiler, so this will be faster, than StringBuffer/append/toString.
But efficient/faster compared to what? Code execution? Code writing? Code reading?
Since reading a
"Foo = " + foo;
is very easy, I would recommend it, as long as it isn't repeated a million times, or a " s += s2;" repeated a hundret times.
Especially,
System.out.println ("Player " + n + " scores " + player[n].score);
is far better readable than
System.out.println (new StringBuffer ("Player ").append ((Integer.valueOf (n)).toString ().append (" scores ").append (...
Just avoid it in applications which need high performance, or concatenate a very large amount of strings, or a large amount recursively.
If you are using multiple times concatenation with '+' , then yes to some extend. Coz
when you do String a + String b , it actually internally creates a StringBuffer object and use append() of StringBuffer. So every time you do a '+' a new temporary StringBuffer object gets created initialized with "a" and then appended with "b", which then gets converted to a string object.
So if you need multiple concatenation you should rather create a StringBuffer(thread-safe)/StringBuilder(not thread safe) object and keep appending, so that you avoid the creation of StringBuffer objects again and again.
According to Netbeans hint named Use chain of .append methods instead of string concatenation
Looks for string concatenation in the parameter of an invocation of the append method of StringBuilder or StringBuffer.
Is StringBuilder.append() really more efficient than strings concatenation?
Code sample
StringBuilder sb = new StringBuilder();
sb.append(filename + "/");
vs.
StringBuilder sb = new StringBuilder();
sb.append(filename).append("/");
You have to balance readability with functionality.
Let's say you have the following:
String str = "foo";
str += "bar";
if(baz) str += "baz";
This will create 2 string builders (where you only need 1, really) plus an additional string object for the interim. You would be more efficient if you went:
StringBuilder strBuilder = new StringBuilder("foo");
strBuilder.append("bar");
if(baz) strBuilder.append("baz");
String str = strBuilder.toString();
But as a matter of style, I think the first one looks just fine. The performance benefit of a single object creation seems very minimal to me. Now, if instead of 3 strings, you had 10, or 20, or 100, I would say the performance outweighs the style. If it was in a loop, for sure I'd use the string builder, but I think just a couple strings is fine to do the 'sloppy' way to make the code look cleaner. But... this has a very dangerous trap lurking in it! Read on below (pause to build suspense... dun dun dunnnn)
There are those who say to always use the explicit string builder. One rationale is that your code will continue to grow, and it will usually do so in the same manner as it is already (i.e. they won't take the time to refactor.) So you end up with those 10 or 20 statements each creating their own builder when you don't need to. So to prevent this from the start, they say always use an explicit builder.
So while in your example, it's not going to be particularly faster, when someone in the future decides they want a file extension on the end, or something like that, if they continue to use string concatenation instead of a StringBuilder, they're going to run into performance problems eventually.
We also need to think about the future. Let's say you were making Java code back in JDK 1.1 and you had the following method:
public String concat(String s1, String s2, String s3) {
return s1 + s2 + s3;
}
At that time, it would have been slow because StringBuilder didn't exist.
Then in JDK 1.3 you decided to make it faster by using StringBuffer (StringBuilder still doesn't exist yet). You do this:
public String concat(String s1, String s2, String s3) {
StringBuffer sb = new StringBuffer();
sb.append(s1);
sb.append(s2);
sb.append(s3);
return sb.toString();
}
It gets a lot faster. Awesome!
Now JDK 1.5 comes out, and with it comes StringBuilder (which is faster than StringBuffer) and the automatic transation of
return s1 + s2 + s3;
to
return new StringBuilder().append(s1).append(s2).append(s3).toString();
But you don't get this performance benefit because you're using StringBuffer explicitly. So by being smart, you have caused a performance hit when Java got smarter than you. So you have to keep in mind that there are things out there you won't think of.
Well, your first example is essentially translated by the compiler into something along the lines:
StringBuilder sb = new StringBuilder();
sb.append(new StringBuilder().append(filename).append("/").toString());
so yes, there is a certain inefficiency here. However, whether it really matters in your program is a different question. Aside from being questionable style (hint: subjective), it usually only matters, if you are doing this in a tight loop.
None of the answers so far explicitly address the specific case that hint is for. It's not saying to always use StringBuilder#append instead of concatenation. But, if you're already using a StringBuilder, it doesn't make sense to mix in concatenation, because it creates a redundant StringBuilder (See Dirk's answer) and an unnecessary temporary String instance.
Several answers already discuss why the suggested way is more efficient, but the main point is, if you already have a StringBuilder instance, just call append on it. It's just as readable (in my opinion, and apparently whoever wrote the NetBeans hint) since you're calling append anyway, and it's a little more efficient.
Theoretically, yes. Because String objects are immutable: once constructed they cannot be changed anymore. So using "+" (concatenation) basically creates a new object each time.
Practically no. The compiler is clever enough to replace all your "+" with StringBuilder appendings.
For a more detailed explanation:
http://kaioa.com/node/59
PS: Netbeans??? Come on!
A concat of two strings is faster using this function.
However, if you have multiple strings or different data type, you should use a StringBuilder either explicitly or implicitly. Using a + with Strings is using a StringBuilder implicitly.
It's only more efficient if you are using lots of concatenation and really long strings. For general-use, such as creating a filename in your example, any string concatenation is just fine and more readable.
At any rate, this part of your application is unlikely to be the performance bottleneck.
In an application a String is a often used data type. What we know, is that the mutation of a String uses lots of memory. So what we can do is to use a StringBuilder/StringBuffer.
But at what point should we change to StringBuilder?
And what should we do, when we have to split it or to remplace characters in there?
eg:
//original:
String[] split = string.split("?");
//better? :
String[] split = stringBuilder.toString().split("?);
or
//original:
String replacedString = string.replace("l","st");
//better? :
String replacedString = stringBuilder.toString().replace("l","st");
//or
StringBuilder replacedStringBuilder = new StringBuilder(stringBuilder.toString().replace("l","st);
In your examples, there are no benefits in using a StringBuilder, since you use the toString method to create an immutable String out of your StringBuilder.
You should only copy the contents of a StringBuilder into a String after you are done appending it (or modifying it in some other way).
The problem with Java's StringBuilder is that it lacks some methods you get when using a plain string (check this thread, for example: How to implement StringBuilder.replace(String, String)).
What we know, is that a String uses lots of memory.
Actually, to be precise, a String uses less memory than a StringBuilder with equivalent contents. A StringBuilder class has some additional constant overhead, and usually has a preallocated buffer to store more data than needed at any given moment (to reduce allocations). The issue with Strings is that they are immutable, which means Java needs to create a new instance whenever you need to change its contents.
To conclude, StringBuilder is not designed for the operations you mentioned (split and replace), and it won't yield much better performance in any case. A split method cannot benefit from StringBuilder's mutability, since it creates an array of immutable strings as its output anyway. A replace method still needs to iterate through the entire string, and do a lot of copying if replaced string is not the same size as the searched one.
If you need to do a lot of appending, then go for a StringBuilder. Since it uses a "mutable" array of characters under the hood, adding data to the end will be especially efficient.
This article compares the performance of several StringBuilder and String methods (although I would take the Concatenation part with reserve, because it doesn't mention dynamic string appending at all and concentrates on a single Join operation only).
What we know, is that the mutation of a String uses lots of memory.
That is incorrect. Strings cannot be mutated. They are immutable.
What you are actually talking about is building a String from other strings. That can use a lot more memory than is necessary, but it depends how you build the string.
So what we can do is to use a StringBuilder/StringBuffer.
Using a StringBuilder will help in some circumstances:
String res = "";
for (String s : ...) {
res = res + s;
}
(If the loop iterates many times then optimizing the above to use a StringBuilder could be worthwhile.)
But in other circumstances it is a waste of time:
String res = s1 + s2 + s3 + s4 + s5;
(It is a waste of time to optimize the above to use a StringBuilder because the Java compiler will automatically translate the expression into code that creates and uses a StringBuilder.)
You should only ever use a StringBuffer instead of a StringBuilder when the string needs to be accessed and/or updated by more than one thread; i.e. when it needs to be thread-safe.
But at what point should we change to StringBuilder?
The simple answer is to only do it when the profiler tells you that you have a performance problem in your string handling / processing.
Generally speaking, StringBuilders are used for building strings rather as the primary representation of the strings.
And what should we do, when we have to split it or to replace characters in there?
Then you have to review your decision to use a StringBuilder / StringBuffer as your primary representation at that point. And if it is still warranted you have to figure out how to do the operation using the API you have chosen. (This may entail converting to a String, performing the operation and then creating a new StringBuilder from the result.)
If you frequently modify the string, go with StringBuilder. Otherwise, if it's immutable anyway, go with String.
To answer your question on how to replace characters, check this out: http://download.oracle.com/javase/tutorial/java/data/buffers.html. StringBuilder operations is what you want.
Here's another good write-up on StringBuilder: http://www.yoda.arachsys.com/csharp/stringbuilder.html
If you need to lot of alter operations on your String, then you can go for StringBuilder. Go for StringBuffer if you are in multithreaded application.
Both a String and a StringBuilder use about the same amount of memory. Why do you think it is “much”?
If you have measured (for example with jmap -histo:live) that the classes [C and java.lang.String take up most of the memory in the heap, only then should you think further in this direction.
Maybe there are multiple strings with the same value. Then, since Strings are immutable, you could intern the duplicate strings. Don't use String.intern for it, since it has bad performance characteristics, but Google Guava's Interner.
Whenever I try to add the numbers in string like:
String s=new String();
for(int j=0;j<=1000000;j++)
s+=String.valueOf(j);
My program is adding the numbers, but very slowly. But When I altered my program and made it like:
StringBuffer sb=new StringBuffer();
for(int j=0;j<=1000000;j++)
sb.append(String.valueOf(j));
I got the result very quickly. Why is that so?
s+=String.valueOf(j); needs to allocate a new String object every time it is called, and this is expensive. The StringBuffer only needs to grow some internal representation when the contained string is too large, which happens much less often.
It would probably be even faster if you used a StringBuilder, which is a non-synchronized version of a StringBuffer.
One thing to note is that while this does apply to loops and many other cases, it does not necessarily apply to all cases where Strings are concatenated using +:
String helloWorld = getGreeting() + ", " + getUsername() + "!";
Here, the compiler will probably optimize the code in a way that it sees fit, which may or may not be creating a StringBuilder, since that is also an expensive operation.
Because s += "string" creates a new instance. A String is immutable. StringBuffer or StringBuilder adds the String without creating a new instance.
In Java as in .NET Strings are immutable. They cannot be changed after creation. The result is that using the +operator will create a new string and copy the contents of both strings into it.
A StringBuffer will double the allocated space every time it runs out of space to add characters. Thus reducing the amount of memory allocations.
Take a look at this, from the Javaspecialists newsletter by Heinz Kabutz:
http://www.javaspecialists.eu/archive/Issue068.html
and this later article:
http://java.sun.com/developer/technicalArticles/Interviews/community/kabutz_qa.html