0

Why someone will use String over StringBuilder.

I am aware of below facts:

  • Advantages of StringBuilder over String,
  • String is immutable ,
  • and we can do everything and more with StringBuilder what String is capable of.
  • And also can't say String is faster because both are non synchronized.

So why someone will use String if StringBuilder is already there ?

akash
  • 22,664
  • 11
  • 59
  • 87
Azam Khan
  • 85
  • 4
  • 11
  • 1
    As per my knowledge concatenation is costly in String as it create a new object. Hence that is an advantage of StringBuilder. – Azam Khan Dec 19 '16 at 09:25
  • Like pointed out to you in a previous comment with link to [another thread](http://stackoverflow.com/questions/1532461/stringbuilder-vs-string-concatenation-in-tostring-in-java), String concatenation is usually compiled to use StringBuilder internally. – eis Dec 19 '16 at 09:27
  • One difference you can see by running this code:'long s = System.currentTimeMillis(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < 100000; i++) { sb.append(i).append("-"); } System.out.println("StringBuilder takes=" + (System.currentTimeMillis() - s)+"ms"); s = System.currentTimeMillis(); String str = ""; for (int i = 0; i < 100000; i++) { str += i+"-"; } System.out.println("String takes=" + (System.currentTimeMillis() - s)+"ms");' StringBuilder is much faster than String – Bahramdun Adil Dec 19 '16 at 09:37
  • I know advantages of StringBUilder over String, I want to know Why String over StringBuilder? – Azam Khan Dec 19 '16 at 09:41
  • The obvious advantage is immutability and the advantages that brings to concurrency. Another point (which is not often stated) is that StringBuilder doesn't override the methods `equals` or `hashCode`. (If it did, it would have been possible to create a `Set` containing duplicates.) Without overriding `equals`, if you want to compare the contents of two `StringBuilder` objects, you have to call `toString()` on both of them and compare their values. So you're back to `String` which defeats the purpose of how you wanted to use `StringBuilder` everywhere. – Klitos Kyriacou Dec 19 '16 at 09:57
  • 1
    @KlitosKyriacou you don't *have to* call toString() to compare the contents, the fastest way is to iterate through (see my example). But yeah, it is still lot less efficient. – eis Dec 19 '16 at 10:59

1 Answers1

1

StringBuilder is mutable, while String is immutable. Immutable means it doesn't change, so your point about it not being synchronized makes no sense - there are no possible changes to be synchronized.

In short, if you don't need StringBuilders extra features (which is common with strings), String is way more efficient. It also has highly optimized, special handling in JVM that other objects in Java don't have.

Most notable example of String-specific optimization, the String pool, makes Strings behave like constants in that the same instance can be shared throughout the application automatically, saving memory and time. This is not automatically possible for other objects, and for mutable objects it is usually not even desired. The String pool, in comparison to custom-made pool, has been shown to allow for more objects with better performance. The process of using only one instance of a String all around for performance benefits is called string interning.

Since you're only using one instance, when comparing, you only need to compare the reference. For each StringBuilder instance, you'd need to evaluate the contents of the object to do that. Stringbuilder uses an Array as a backing object and that Array has to be iterated through to get its contents, which is considerably more costly. This assuming you're interested about the string contents and not the object instance, which is almost always the case with String/StringBuilder/StringBuffer.


Simple performance test comparing for contents of String and StringBuilder:

public class CompTest {

  // fastest way to compare StringBuilder contents according to
  // http://stackoverflow.com/questions/11007387/what-is-an-efficient-way-to-compare-stringbuilder-objects
  static boolean contentEquals(StringBuilder sb1, StringBuilder sb2) {
    if (sb1.length() != sb2.length()) return false;
    for (int i = 0, len = sb1.length(); i < len; i++) {
      if (sb1.charAt(i) != sb2.charAt(i)) return false;
    }
    return true;
  }

  public static void main(String args[]) {

    StringBuilder fooSb = new StringBuilder("foo");
    StringBuilder barSb = new StringBuilder("foo");
    String foo = "foo";
    String bar = "foo";

    System.out.println(foo.equals(bar));
         // returns true
    System.out.println(fooSb.equals(barSb));
         // returns false, so cannot be used to check contents
    System.out.println(contentEquals(fooSb,barSb));
         // returns true

    long time;

    time = System.currentTimeMillis();
    for (int i = 0; i < 2000000000; i++) {
      if (foo.equals(bar)) continue;
    }
    System.out.println("str comparisons took " + (System.currentTimeMillis() - time) + " ms");

    time = System.currentTimeMillis();
    for (int i = 0; i < 2000000000; i++) {
      if (contentEquals(fooSb,barSb)) continue;
    }
    System.out.println("sb comparisons took " + (System.currentTimeMillis() - time) + " ms");

    /* repeat the test as we know JVM is warmed up by now */

    time = System.currentTimeMillis();
    for (int i = 0; i < 2000000000; i++) {
      if (foo.equals(bar)) continue;
    }
    System.out.println("str comparisons took " + (System.currentTimeMillis() - time) + " ms");

    time = System.currentTimeMillis();
    for (int i = 0; i < 2000000000; i++) {
      if (contentEquals(fooSb,barSb)) continue;
    }
    System.out.println("sb comparisons took " + (System.currentTimeMillis() - time) + " ms");

 }
}

With results:

true
false
true
str comparisons took 1244 ms
sb comparisons took 11530 ms
str comparisons took 1231 ms
sb comparisons took 12098 ms
eis
  • 51,991
  • 13
  • 150
  • 199
  • 1
    I put that fact because if you check StringBuilder and StringBuffer, the only difference you will find the performance, Because StringBuffer's methods are synchronized and take more time to execute. here I put this fact because I know String and StringBuilder both are non synchronized , hence this can not be a reason to use String over StringBuilder. – Azam Khan Dec 19 '16 at 09:38
  • In what way String is more efficient than StringBuilder, Can you please explain? – Azam Khan Dec 19 '16 at 09:39
  • @AzamKhan You are right. I have tested StringBuilder vs String, StringBuilder was much faster than String. – Bahramdun Adil Dec 19 '16 at 09:41
  • @BahramdunAdil you have only tested string concatenation, which is not relavant to my answer. – eis Dec 19 '16 at 10:02
  • @BahramdunAdil `StringBuilder` is faster than `String` in certain situations, not in all cases. – Klitos Kyriacou Dec 19 '16 at 10:03
  • @AzamKhan added some details – eis Dec 19 '16 at 10:17
  • @eis , Thanks Eis, Its really good explanation and make more sense . Yeah string pool allows string constants to be reused, which is possible because strings in Java are immutable. If we repeat the same string constant all over the place in our Java code, we can actually have only one copy of that string in your system, which is one of the advantages of this mechanism. – Azam Khan Dec 19 '16 at 10:21
  • Also added note about StringBuilder always backing to char[] array. That is way more costly to check against than just a reference, as in String case. – eis Dec 19 '16 at 10:23
  • @AzamKhan added also a simple performance test case – eis Dec 19 '16 at 10:52
  • Note, however, that this optimization will only happen if both strings are interned. If either string is not interned (e.g. if you are testing an input string against a set of interned strings) then a full char array comparison will take place. – Klitos Kyriacou Dec 19 '16 at 11:00
  • @AzamKhan is there still something to be added for the answer to be accepted? – eis Dec 31 '16 at 11:22