2

I have read in a Java book that says:

Because a String is immutable, using StringBuffer is more efficient.

I understand that String instances are immutable.

I also understand that StringBuffer makes processing Strings more effcient than normal.

But the thing I can't work out is what connects these two concepts, i.e. how does String being immutable help StringBuffer?

Thanks :)

K Mehta
  • 10,323
  • 4
  • 46
  • 76
hqt
  • 29,632
  • 51
  • 171
  • 250
  • 2
    Being immutable makes String slower. Thus, StringBuffer becomes a better alternative. There should be no direct linkage between the two. – Chetter Hummin Mar 28 '12 at 03:25
  • From the Javadoc for StringBuffer in Java 5.0 from 2004 `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. ` If you are concerned about performance, don't use StringBuffer. – Peter Lawrey Mar 28 '12 at 07:13
  • 1
    @AmitBhargava - Immutable Strings are slower for some things, but faster for others. For instance, substring (with usable semantics) is typically faster than if String was mutable, because it is not necessary to copy the characters. But I'd agree that **overall**, immutability makes Strings slower (probably). – Stephen C Apr 05 '12 at 04:22

5 Answers5

8

Because Strings are immutable, to manipulate Strings, such as to concatenate Strings, you have to create new String objects, since obviously, you can't change the state of existing String objects. Whereas with a StringBuffer or StringBuilder, you create one object and simply change its state. If you're doing some major String concatenation in a for loop for instance, this object creation can get very expensive.

That being said, I see many posts here critical of simple String concatenation that don't involve large-scale concatenation, and in that situation using a StringBuffer or StringBuilder is an example of premature and unnecessary optimization.

Also note that you should use StringBuilder preferentially over StringBuffer unless your application needs to access the object in multiple threads and doesn't mind the extra overhead that this incurs.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • 1
    Oh. It means: if I want to concatenate String "abc" and "def" but not using Buffer. In String pool will have: "abc" "abcd" "abcde" "abcdef". But if use buffer, just have "abc", "abcdef", "def". Right ? – hqt Mar 28 '12 at 03:28
  • Incorrect. First off, your example is trivial and would suggest that simply using Strings is the best way to go. The pool would have "abc", "def" and "abcdef" for simply using Strings. – Hovercraft Full Of Eels Mar 28 '12 at 03:31
  • 1
    @hqt - no, there will just be abc, def, and abcdef. But imagine concatenating 10 or more strings together in a loop - then you'd get a new string for each concatenation. On the other hand, the compiler will optimize where it can. For instance, literal `"abc" + "def"` is concatenated at compile-time, not runtime. And if you do multiple runtime concatenations in a single statement, it will make one StringBuilder and do appends - just as you would write by hand using StringBuilder yourself. See http://stackoverflow.com/questions/1532461. – Ed Staub Mar 28 '12 at 03:36
  • +1 for pointing out that using `StringBuilder` is more efficient (since efficiency was the point of not using Strings) than `StringBuffer` when not having to worry about concurrency. – Amos M. Carpenter Mar 28 '12 at 04:06
  • It should be noted that the reason that the hand optimization (Hovercraft's 2nd paragraph) is unnecessary is that the Java compiler can and will do effectively the same optimization itself ... – Stephen C Mar 29 '12 at 23:19
2

What it meant to say to is that since String is immutable therefore it is better to use StringBuffer (or StringBuilder) for String manipulation since you're not creating new object every time you change underlying String.

anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 1
    Oh. It means: if I want to concatenate String "abc" and "def" but not using Buffer. In String pool will have: "abc" "abcd" "abcde" "abcdef". But if use buffer, just have "abc", "abcdef", "def". Right ? – hqt Mar 28 '12 at 03:32
1

All the other posts definitely answer the question. I would add that you should always choose StringBuilder over StringBuffer. StringBuffer has built-in thread synchronization, which is a whole lot of locking overhead that you will almost never need. StringBuilder does not have this, and is therefore faster.

In fact, even if you want thread safety, here are some very good reasons not to use StringBuffer.

sparc_spread
  • 10,643
  • 11
  • 45
  • 59
1

But the thing I can't work out is what connects these two concepts, i.e. how does String being immutable help StringBuffer?

It doesn't. I think that you are simply misinterpreting the sentence that you quoted.

"Because a String is immutable, using StringBuffer is more efficient."

It is saying that StringBuffer is a relative more efficient option (for certain tasks). In other words: "Because a String is immutable, using StringBuffer is more efficient [than using String for certain tasks].".

It is NOT saying that StringBuffer is faster in absolute terms than it would be if String wasn't immutable. Certainly, that's not how I read the quote ... and it is not a true statement either.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

The concept of immutable can easily be explained with this example

String s1 = "Hello";
String s2 = "Hi";
String s3 = "Hello";

if (s1 == s2){ System.out.println("s1==s2");}
if (s1 == s3){ System.out.println("s1==s3");}

s1 = "Hi";

if (s1 == s2){ System.out.println("s1==s2");}
if (s1 == s3){ System.out.println("s1==s3");}

If you execute this piece of code you would get s1==s3 and s1==s2. What does this example explains?

When you created s1, the compiler created a string "Hello" in its string table (i dun remember its exact name). When you created s2, it create new object "Hi". Now when you created s3, compiler knows that there is an object "Hello" already in its string table, so why not just refer s3 to it. So s1=s3 (memory vise). Same happened when you assigned value "hi" to s1, compiler could see that "hi" is already in the memory being pointed by s3, so it pointed it to s1 as well.

In case of StringBuffer, Compiler allocates memory to the object, which you can manipulate rather "pool" as in case of String.

hqt
  • 29,632
  • 51
  • 171
  • 250
Em Ae
  • 8,167
  • 27
  • 95
  • 162