Search code examples
javastringimmutabilitystringbuildermutable

Are Strings *really* immutable in Java?


Everyone knows that Java's String object is immutable which essentially means that if you take String object a and concatenate it with another String object, say b, a totally new String object is created instead of an inplace concatenation.

However, recently I have read this question on SO which tells that the concatenation operator + is replaced with StringBuilder instances by the compiler.

At this point, I get a bit confused since, as far as I know and think, the StringBuilder objects are mutable due to their internal structure. In this case, wouldn't this essentially make String objects in Java mutable ?


Solution

  • Not really.

    The actual Strings are still immutable, but in compile time, the JVM can detect some situations where the creation of additional String objects can be replaced by a StringBuilder.

    So if you declare a String a and concatenate with another String, your a object doesn't change, (since it's immutable), but the JVM optimizes this by replacing the concatenation with the instantiation of a StringBuilder, appending both Strings to the Builder, and finally assigning the resulting String.

    Let's say you have:

    String a = "banana";
    String d = a + "123" + "xpto";
    

    Before the JVM optimized this, you would essentially be creating a relatively large number of Strings for something so simple, namely:

    • String a
    • String "123"
    • String "xpto"
    • String a + "123"
    • String a+"123"+"xpto"

    With the optimization of transforming concatenation into a StringBuilder, the JVM no longer needs to create the intermediate results of the concatenation, so only the individual Strings and the resulting one are needed.

    This is done basically for performance reasons, but keep in mind that in certain situations, you'll pay a huge penalty for this if you aren't careful. For instance:

    String a = "";
    for(String str: listOfStrings){
        a += str;
    }
    

    If you were doing something like this, in each iteration the JVM will be instantiating a new StringBuilder, and this will be extremely costly if listOfStrings has a lot of elements. In this case, you should use a StringBuilder explicitly and do appends inside the loop instead of concatenating.