tags:

views:

659

answers:

10

Please tell me a real time situation to compare String, StringBuffer, and StringBuilder?

+1  A: 

Do you mean, for concatenation?

Real world example: You want to create a new string out of many others.

For instance to send a message:

String

String s = "Dear " + user.name + "<br>" + 
" I saw your profile and got interested in you.<br>" +
" I'm  " + user.age + "yrs. old too"

StringBuilder

String s = new StringBuilder().append.("Dear ").append( user.name ).append( "<br>" ) 
          .append(" I saw your profile and got interested in you.<br>") 
          .append(" I'm  " ).append( user.age ).append( "yrs. old too")
          .toString()

Or

String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as  fuzzy lollipop points out.

StringBuffer ( the syntax is exactly as with StringBuilder, the effects differ )

About

StringBuffer vs. StringBuilder

The former is synchonized and later is not.

So, if you invoke it several times in a single thread ( which is 90% of the cases ), StringBuilder will run much faster because it won't stop to see if it owns the thread lock.

So, it is recommendable to use StringBuilder ( unless of course you have more than one thread accessing to it at the same time, which is rare )

String concatenation ( using the + operator ) may be optimized by the compiler to use StringBuilder underneath, so, it not longer something to worry about, in the elder days of Java, this was something that everyone says should be avoided at all cost, because every concatenation created a new String object. Modern compilers don't do this anymore, but still it is a good practice to use StringBuilder instead just in case you use an "old" compiler.

edit

Just for who is curious, this is what the compiler does for this class:

class StringConcatenation {
    int x;
    String literal = "Value is" + x;
    String builder = new StringBuilder().append("Value is").append(x).toString();
}

javap -c StringConcatenation

Compiled from "StringConcatenation.java"
class StringConcatenation extends java.lang.Object{
int x;

java.lang.String literal;

java.lang.String builder;

StringConcatenation();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   new #2; //class java/lang/StringBuilder
   8:   dup
   9:   invokespecial   #3; //Method java/lang/StringBuilder."<init>":()V
   12:  ldc #4; //String Value is
   14:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   17:  aload_0
   18:  getfield    #6; //Field x:I
   21:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   24:  invokevirtual   #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   27:  putfield    #9; //Field literal:Ljava/lang/String;
   30:  aload_0
   31:  new #2; //class java/lang/StringBuilder
   34:  dup
   35:  invokespecial   #3; //Method java/lang/StringBuilder."<init>":()V
   38:  ldc #4; //String Value is
   40:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   43:  aload_0
   44:  getfield    #6; //Field x:I
   47:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   50:  invokevirtual   #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   53:  putfield    #10; //Field builder:Ljava/lang/String;
   56:  return

}

Lines numbered 5 - 27 are for the String named "literal"

Lines numbered 31-53 are for the String named "builder"

Ther's no difference, exactly the same code is executed for both strings.

OscarRyz
this is a really bad example. Initializing the StringBuilder with " Dear " means the first .append() will cause a reallocation and copy. Completely negating any efficiency that you are trying to gain over "normal" concatenation. A better example would to be to create it with a initial size that will hold the entire contents of the final String.
fuzzy lollipop
It is NOT generally a good practice to use a `StringBuilder` to do String concatenation on the right-hand side of the assignment. Any good implementation will use a StringBuilder behind the scenes as you say. Furthermore, your example of `"a" + "b"` would be compiled into a single literal `"ab"` but if you used `StringBuilder` it would result in two needless calls to `append()`.
Mark Peters
@Mark I didn't mean to use `"a"+"b"` but to say what was a *String concatenation* about I change it to be explicit. What you don't say is, why is not a good practice to do it. That's exactly what ( a modern ) compiler does. @fuzzy, I agree, specially when you know what the size of the final string would be ( aprox ) .
OscarRyz
@Support: I don't think it's particularly *bad* practice, but I certainly wouldn't want any recommendation to do that in general. It's clunky and hard to read, and overly verbose. Plus, it encourages mistakes like yours where you are breaking up two literals that could otherwise be compiled as one. Only if profiling told me it made a difference would I do it your way.
Mark Peters
@Mark Got it. I was thinking more in the *"big chunk of code like a template"* and not really in every regular string literal. But yes, I agree, since they do the same thing nowadays, it doesn't make sense ( 10 yrs ago was a reason to reject a change in a code revision ) :)
OscarRyz
A: 

Also, StringBuffer is thread-safe, which StringBuilder is not.

So in a real-time situation when different threads are accessing it, StringBuilder could have an undeterministic result.

Lars Andren
+8  A: 
  • You use String when you are dealing with immutable strings.
  • You use StringBuilder when you need to create a mutable character sequence, usually to concatenate several character sequences together.
  • You use StringBuffer in the same circumstances you would use StringBuilder, but when changes to the underlying string must be synchronized (because several threads are reading/modifyind the string buffer).

See an example here.

Artefacto
+1, concise answer.
Dolph
concise, but incomplete, it misses the fundamental reason to use StringBuilder/Buffer and that is to reduce or eliminate the re-allocation and array copy of the regular String concatenation behavior.
fuzzy lollipop
A: 

When you are using String, you are making a new String each time you are adding 2 of them.

When you are using StringBuilder, it uses a buffer to make less String addition and will therefore be more performant when you want to add a lot of string one after the other.

StringBuffer is the exact same thing as of StringBuilder except that all his method are synchronized. The only use of that class is if you need to share the buffer with multiple thread (which rarely happends).

HoLyVieR
+21  A: 

Mutability Difference:

String is immutable, if you try to alter their values, another object gets created, whereas StringBuffer and StringBuilder are mutable so they can change their values.

Thread-Safety Difference:

The difference between StringBuffer and StringBuilder is that StringBuffer is thread-safe. So when the application needs to be run only in a single thread then it is better to use StringBuilder. StringBuilder is more efficient than StringBuffer.

Situations:

  • If your string is not going to change use a string Class because a String object is immutable.
  • If your string can change (example: lots of logic and operations in the construction of the string) and will only be accessed from a single thread, use a StringBuilder is good enough.
  • If your string can change, and will be accessed from multiple threads, use a StringBuffer because StringBuffer is synchronous so you have thread-safety.
Bakkal
Also, using String for logic operations is rather slow, and is not advised at all, since the JVM converts the String to a StringBuffer in the bytecode. A lot of overhead is wasted converting from String to StringBuffer and then back to String again.
Pieter van Niekerk
+2  A: 

The Basics:

String is an immutable class, it can't be changed. StringBuilder is a mutable class that can be appended to, characters replaced or removed and ultimately converted to a String StringBuffer is the original synchronized version of StringBuilder

You should prefer StringBuilder in all cases where you have only a single thread accessing your object.

The Details:

Also note that StringBuilder/Buffers aren't magic, they just use an Array as a backing object and that Array has to be re-allocated when ever it gets full. Be sure and create your StringBuilder/Buffer objects large enough originally where they don't have to be constantly re-sized every time .append() gets called.

The re-sizing can get very degenerate. It basically re-sizes the backing Array to 2 times its current size every time it needs to be expanded. This can result in large amounts of RAM getting allocated and not used when StringBuilder/Buffer classes start to grow large.

In Java String x = "A" + "B"; uses a StringBuilder behind the scenes. So for simple cases there is no benefit of declaring your own. But if you are building String objects that are large, say less than 4k, then declaring StringBuilder sb = StringBuilder(4096); is much more efficient than concatenation or using the default which is only 16 characters. If your String is going to be less than 10k then initialize it with the constructor to 10k to be safe. But if it is initialize to 10k then you write 1 character more than 10k, it will get re-allocated and copied to a 20k array. So initializing high is better than to low.

In the auto re-size case, at the 17th character the backing Array gets re-allocated and copied to 32 characters, at the 33th character this happens again and you get to re-allocated and copy the Array into 64 characters. You can see how this degenerates to lots of re-allocations and copies which is what you really are trying to avoid using StringBuilder/Buffer in the first place.

This is from the JDK 6 Source code for AbstractStringBuilder

   void expandCapacity(int minimumCapacity) {
    int newCapacity = (value.length + 1) * 2;
        if (newCapacity < 0) {
            newCapacity = Integer.MAX_VALUE;
        } else if (minimumCapacity > newCapacity) {
        newCapacity = minimumCapacity;
    }
        value = Arrays.copyOf(value, newCapacity);
    }

A best practice is to initialize the StringBuilder/Buffer a little bit larger than you think you are going to need if you don't know right off hand how big the String will be but you can guess. One allocation of slightly more memory than you need is going to be better than lots of re-allocations and copies.

Also beware of initializing a StringBuilder/Buffer with a String as that will only allocated the size of the String + 16 characters, which in most cases will just start the degenerate re-allocation and copy cycle that you are trying to avoid. The following is straight from the Java 6 source code.

public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
    }

If you by chance do end up with an instance of StringBuilder/Buffer that you didn't create and can't control the constructor that is called, there is a way to avoid the degenerate re-allocate and copy behavior. Call .ensureCapacity() with the size you want to ensure your resulting String will fit into.

The Alternatives:

Just as a note, if you are doing really heavy String building and manipulation, there is a much more performance oriented alternative called Ropes.

Another alternative, is to create a StringList implemenation by sub-classing ArrayList<String>, and adding counters to track the number of characters on every .append() and other mutation operations of the list, then override .toString() to create a StringBuilder of the exact size you need and loop through the list and build the output, you can even make that StringBuilder an instance variable and 'cache' the results of .toString() and only have to re-generate it when something changes.

Also don't forget about String.format() when building fixed formatted output, which can be optimized by the compiler as they make it better.

fuzzy lollipop
Does `String x = "A" + "B";` really compile to be a StringBuilder? Why wouldn't it just compile to `String x = "AB";`, it should only use a StringBuilder if the components aren't known at compile time.
Matt Greer
it might optimize the String constants out, I can't recall from the last time decompiled the byte code, but I do know that if there are any variables in there it will use a StringBuilder implementation for sure. You can download the JDK source code and find out yourself. "A" + "B" is a contrived example for sure.
fuzzy lollipop
I was wondering about String.format(). I haven't ever really seen it being used in projects. Usually it's the StringBuilder. Well, usually it's actually "A" + "B" + "C" because people are lazy ;) I tended to always use a StringBuilder, even if it was only two strings being concatenated, because in future, perhaps more strings would be appended. I never used String.format() mainly because I never remembered what JDK it was introduced - I see it's JDK1.5, I'd use it in favour of the other options.
jamiebarrow
+3  A: 

This is a very good article http://kaioa.com/node/59

Sujee
better article http://java.sun.com/developer/technicalArticles/Interviews/community/kabutz_qa.html
fuzzy lollipop
Hi fuzzy lollipop,I do not understand your intension. If the article you have posted is better doesn't mean that my article is wrong. You should give -1 only if it is giving faulty info.
Sujee
A: 

Note that if you are using Java 5 or newer, you should use StringBuilder instead of StringBuffer. From the API documentation:

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.

In practice, you will almost never use this from multiple threads at the same time, so the synchronization that StringBuffer does is almost always unnecessary overhead.

Jesper
A: 

Personally, I don't think there is any real world use for StringBuffer. When would I ever want to communicate between multiple threads by manipulating a character sequence? That doesn't sound useful at all, but maybe I have yet to see the light :)

FredOverflow
A: 

Has anyone else had good experiences with Ropes as a String replacement? I use a lot of JSP tags in my web app which use StringBuilder heavily, but which makes the code ugly and hard to read.

Nicholas Tolley Cottrell