2

I've always wondered why does JAVA and C# has String (immutable & threadsafe) class, if they have StringBuilder (mutable & not threadsafe) or StringBuffer (mutable & threadsafe) class. Isn't StringBuilder/StringBuffer superset of String class? I mean, why should I use String class, if I've option of using StringBuilder/StringBuffer?

For example, Instead of using following,

String str;

Why can't I always use following?

StringBuilder strb; //or
StringBuffer strbu;

In short, my question is, How will my code get effected if I replace String with StringBuffer class? Also, StringBuffer has added advantage of mutability.

Abhishek
  • 6,912
  • 14
  • 59
  • 85
  • 1
    In some situation it is beneficiary to use string instead of stringbuilder. remember string is flyweight. I am just finding some link that can provide you with proof. – Jenish Rabadiya May 20 '15 at 12:46
  • What do you mean by flyweight? – Abhishek May 20 '15 at 12:47
  • Hah? String is used in so many ways and it is good to have this immutable class. StringBuilder and -Buffer are used to create/build Strings - why should they be used to *replace* Strings? I don't get it why you don't get it! – Alexander May 20 '15 at 12:51
  • @Abhishek look at [here](http://en.wikipedia.org/wiki/Flyweight_pattern). String's interning nature makes it more proficient. – Jenish Rabadiya May 20 '15 at 13:00
  • @JenishRabadiya Got it. So, `String` will make only one copy for every distinct string literal. That could be a problem, I mean what happens if string pool if filled? – Abhishek May 21 '15 at 04:24
  • @Abhishek You are right that could be a problem but in more scenarios that is beneficiary. Look at [Jon Skeet's answer](http://stackoverflow.com/a/30350176/1505865) below. – Jenish Rabadiya May 21 '15 at 04:53
  • As they aren't supersets, your question is based on a false premiss. – user207421 May 27 '15 at 10:52

6 Answers6

16

I mean, why should I use String class, if I've option of using StringBuilder/StringBuffer?

Precisely because it's immutable. Immutability has a whole host of benefits, primarily that it makes it much easier to reason about your code without creating copies of the data everywhere "just in case" something decides to mutate the value. For example:

private readonly String name;

public Person(string name)
{
    if (string.IsNullOrEmpty(name)) // Or whatever
    {
        // Throw some exception
    }
    this.name = name;
}

// All the rest of the code can rely on name being a non-null 
// reference to a non-empty string. Nothing can mutate it, leaving
// evil reflection aside.

Immutability makes sharing simple and efficient. That's particularly useful for multi-threaded code. It makes "modifying" (i.e. creating a new instance with different data) more painful, but in many situations that's absolutely fine, because values pass through the system without ever being modified.

Immutability is particularly useful for "simple" types such as strings, dates, numbers (BigDecimal, BigInteger etc). It allows them to be used within maps more easily, it allows a simple equality definition, etc.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    I can replace `private readonly String name;` with `private readonly StringBuffer name;`, isn't it? How will it effect my code? I mean, I get desired result with `StringBuffer` and added advantage of mutability. So, why should I use `String`? – Abhishek May 20 '15 at 12:54
  • 7
    @Abhishek: "and added advantage of mutability" - no, that's a *disadvantage*. It would mean someone could call `Person p = new Person(builder);` with a builder which *initially* passes my validation criteria - and then modify it afterwards, without the `Person` class having any say in it. In order to avoid that, the `Person` class would need to copy the validated data. Mutability is a huge *problem*, not an advantage. The key to software design is managing complexity - and widescale mutability is a massive enemy of that. – Jon Skeet May 20 '15 at 12:57
  • If immutability was only an advantage, we would no longer see imperative code like Java or C# but only see functional languages. If mutability was only an advantage, we would not see functional languages at all. As both of them are quite popular, neither is the case. – Georg May 20 '15 at 13:04
  • @Georg: Right, which is why I talk about it making modification more painful. But for some types (such as `String`) the benefits of immutability far outweight the downsides for most uses. I'd argue that `java.util.Date` and several similar classes should *also* be immutable... – Jon Skeet May 20 '15 at 13:06
  • @JonSkeet I totally agree. It is a bit like the Haskell-programmers replacing the entire house to change the light-bulb. For strings and a lot of other types like Date, this is reasonable unless the strings get too long. In fact, the fact that the Date type is immutable in .NET supports this argumentation. – Georg May 20 '15 at 13:13
  • Don't forget that immutability makes using String values as keys in maps a whole lot more sensible.... – rolfl May 20 '15 at 13:16
  • @JonSkeet I can use `StringBuffer` for `Person p = new Person(buffer);` and it will be thread safe. So, it wouldn't matter in that scenario, right? – Abhishek May 20 '15 at 13:35
  • @Abhishek: Threading is only one part of the benefit. I could still write `buffer.setLength(0)` afterwards, leaving an invalid `Person` object despite it having been valid at construction time. No need for multiple threads. – Jon Skeet May 20 '15 at 13:38
  • @JonSkeet then it would be bad coding, isn't it? I mean if I'm using single thread then I wouldn't do it. If I do it, it would be a bug on my part. – Abhishek May 20 '15 at 13:39
  • @Abhishek: Yes, it would be a bug - but one that was really easy to introduce, due to mutability. It's hard to keep it clear what can be mutated and what can't - so you end up either copying things everywhere, or never *actually* mutating things even though the compiler doesn't stop you. That doesn't sound like a good thing to me. – Jon Skeet May 20 '15 at 13:40
  • @Abhishek It would matter, of course, in the example in particular because the name is readonly. Then `string` would not allow any changes whereas `StringBuffer` does. Even if name was not readonly, the change has a great impact (also see my answer for details). – Georg May 20 '15 at 13:42
  • @JonSkeet So, is it just a programming paradigm and help programmers to debug code easily? – Abhishek May 20 '15 at 13:43
  • 2
    @Abhishek: It's an approach which allows programmers to manage complexity, making it easier to reason about their code. That goes a long way beyond debugging. – Jon Skeet May 20 '15 at 13:44
  • @JonSkeet Understood. Thanks for helping me out. One more question, so `String` objects will perform better than `StringBuffer`/`StringBuilder` objects in any scenario? :) – Abhishek May 21 '15 at 04:56
  • @Abhishek: That's too vague a question to answer. Being immutable allows strings to be shared with just a copy of the reference... So at the very least, scenarios where multiple classes want to be assured that their data doesn't change but they want to share values will work better with strings... Does that count in your view? – Jon Skeet May 21 '15 at 05:13
3

1) StringBuilder as well as StringBuffer both are mutable. So it will cause a few problems like using in collections like keys in hashMap. See this link.

Another example of advantage of immutability will be what Jon has mentioned in his comments. I am just pasting here.

Someone can call Person p = new Person(builder); with a builder which initially passes my validation criteria - and then modify it afterwards, without the Person class having any say in it. In order to avoid that, the Person class would need to copy the validated data.

Immutabilty assures this does not happen.

2) As string is most extensively used object in java, the string pool offers to resuse same string, thus saving memory.

Community
  • 1
  • 1
Vivek Vardhan
  • 1,118
  • 3
  • 21
  • 44
  • I can use `StringBuffer`, if thread safety is the issue. How does String help in reuse of memory? I mean `StringBuffer` or `StringBuilder` objects are also stored in memory location, which can be reused. – Abhishek May 20 '15 at 12:51
  • @Abhishek You wil need to write a specific function that searches the memory and returns the string for you, now suppose at some places string got changed, all the instances using it will change, which might not be the requirement. Here again comes `immutability` of string useful. This is the biggest factor – Vivek Vardhan May 20 '15 at 13:10
  • I'll use `StringBuffer` (thread-safety), so I don't have to worry about somebody changing data. – Abhishek May 20 '15 at 13:41
0

I completely agree with Jon Skeet that immutability is one reason to use String. Another reason (from a C# perspective) is that String is actually lighter weight than StringBuilder. If you look at reference source for both String and String Builder you will see that StringBuilder actually has a number of String constants in it. As a developer, you should only use what you need so unless you need the added benefits provided from StringBuilder you should use String.

Community
  • 1
  • 1
David
  • 236
  • 1
  • 12
0

Many answers have already outlined that there are shortcomings from using mutable variants such as StringBuilder. To illustrate the problem, one thing that you cannot achieve with StringBuilder is associative memory, i.e. hash tables. Sure, most implementations will allow you to use StringBuilder as a key for hashtables, but they will only find the values for the exact same instance of StringBuilder. However, the typical behavior that you would want to achieve is that it does not matter where the string comes from as only the characters are important, as you e.g. reade the string from a database or file (or any other external resource).

However, as far as I understood your question, you were mainly asking about field types. And indeed, I see your point particularly taking into account that we are doing the exact same thing with collections of other objects which are usually not immutable objects but mutable collections, such as List or ArrayList in C# or Java, respectively. In the end, a string is only a collection of characters, so why not making it mutable?

The answer I would give here is that the usual behavior of how such a string is changed is very different to usual collections. If you have a collection of subsequent elements, it is very common to only add a single element to the collection, leaving most of the collection untouched, i.e. you would not discard a list to insert an item, at least unless you are programming in Haskell :). For many strings like names, this is different as you typically replace the whole string. Given the importance of a string data type, the platforms usually offer a lot of optimization for strings such as interned strings, making the choice even more biased towards strings.

However, in the end, every program is different and you might have requirements that make it more reasonable to use StringBuilder by default, but for the given reasons, I think that these cases are rather rare.

EDIT: As you were asking for examples. Consider the following code:

stopwatch.Start();
var s = "";
for (int i = 0; i < 100000; i++)
{
    s = "." + s;
}
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);

stopwatch.Restart();
var s2 = new StringBuilder();
for (int i = 0; i < 100000; i++)
{
     s2.Insert(0, ".");
}
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);

Technically, both bits are doing a very similar thing, they will insert a character at the first position and shift whatever comes after. Both versions will involve copying the whole string that has been there before. The version with string completes in 1750ms on my machine whereas StringBuilder took 2245ms. However, both versions are reasonably fast, making the performance impact negligible in this case.

Georg
  • 5,626
  • 1
  • 23
  • 44
  • You said optimization. What kind of optimization you mean? I mean is String better in performance than StringBuffer? How? When is it? Can you share example? – Abhishek May 20 '15 at 13:47
  • I updated the answer to include an example.However, I don't know what exactly is done in this optimization. – Georg May 20 '15 at 14:04
  • However, I just checked, it seems like this is not really an optimization, a dumb list of chars takes about 1000ms. – Georg May 20 '15 at 14:06
  • Exactly! So, I still don't understand why should I choose `String` over `StringBuffer`. If need, simple append/insert like these I'll go with char array, as you said :) – Abhishek May 20 '15 at 16:00
  • Maybe another argument is that as soon as you start doing something with the strings, you will need them as `string` in most applications. If you use `StringBuffer` all along, you will need conversions that are not really memory efficient, but as I said, if you are sure that this is the best for your application, go ahead. – Georg May 21 '15 at 14:33
  • Yup, I knew that `StringBuffer` implicitly uses `String`. It was one of the reason for my confusion. – Abhishek May 21 '15 at 16:26
0

I would like to add some differences between String and StringBuilder classes:

Yes, as mentioned above String is immutable class and content cannot be changed after string has been created. It is allow to work with the same string objects from different threads without locking. If you need to concatenate a lot of strings together, use StringBuilder class. When you use "+" operator it creates a lot of string objects on managed heap and hurts performance.

StringBuilder is mutable class. StringBuilder stores characters in array and can manipulate with characters without creating a new string object (such as add, remove, replace, append). If you know approximate length of result string you should set capacity. Default capacity is 16 (.NET 4.5). It gives you performance improvements because StringBuilder has inner array of chars. Array of chars recreates when count of characters exceeds current capacity.

Didgeridoo
  • 1,222
  • 2
  • 14
  • 21
-1

String:

  • is immutable (so you can use it in collections)
  • every operation creates a new instance on the Heap. Technically speaking really depends on the code.

For performance and memory consumption purposes it makes sense to use StringBuilder.

Crazyjavahacking
  • 9,343
  • 2
  • 31
  • 40