We Don’t Need StringBuilder for Simple Concatenation

Posted on by

Categories:     

String concatenation has always been a well-discussed topic among Java developers. It’s been costly.

Let’s first dig into the issue of why it’s costly.

In Java, string objects are immutable, which means once it is created, you cannot change it. So when we concatenate one string with another, a new string is created, and the older one is marked for the garbage collector.

string object an immutable

Let’s say we need to concatenate a million strings. Then, we are creating 1 million extra strings which will eventually be garbage collected.

In string concatenation, under the hood, several operations occur. Using the dot operator to concatenate string is equivalent to using the String#concat(String) method.

    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
    
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
    
        return new String(buf, true);
    }

    public static char[] copyOf(char[] original, int newLength) {
        char[] copy = new char[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

    void getChars(char dst[], int dstBegin) {
        System.arraycopy(value, 0, dst, dstBegin, value.length);
    }

As you can see, a new array of characters is created with a size of the length of the existing value plus the size of value that is appended. Then, their value is copied to the new array instance. Finally, a new String object is created from the array and returned.

So it’s a lot of operations, which ends up being O(n^2) complexity — if you really want to calculate this issue out.

To solve this problem, the StringBuilder class is used. It works like a mutable String object. The append method helps to avoid all the copying required in string concatenation. It has O(n) complexity, which is better than O(n^2).

However, Java does this string concatenation using StringBuilder by default for the simple cases..

From the Java specifications:

To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.

Well, the Java compiler does that.

    public class StringConcatenateDemo {
      public static void main(String[] args) {
         String str = "Hello ";
         str += "world";
       }
    }

The above code will produce the following bytecode:

    public class StringConcatenateDemo {
      public StringConcatenateDemo();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
      public static void main(java.lang.String[]);
        Code:
           0: ldc           #2                  // String Hello
           2: astore_1
           3: new           #3                  // class java/lang/StringBuilder
           6: dup
           7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
          10: aload_1
          11: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          14: ldc           #6                  // String world
          16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
          22: astore_1
          23: return
    }

As you can see in the bytecode, StringBuilder is used. So we don’t need to use StringBuilder anymore in Java.

However, This is true for the simple cases. If you need to concatenate inside the loop, it is always suggested to use StringBuilder.

TL; DR

For simple string concatenation, you need not use StringBuilder, java compiler will do the trick for you. However, if you need to concatenate inside a loop, you need to manually apply StringBuilder.

For better understanding please go to this link.

Edit: The earlier I made this case with only Java 8. Turns out I was wrong. So I stand correct myself. It has nothing to do with java 8.

     

Share on:

Author: A N M Bazlur Rahman

Java enthusiastic | Book author | Mentor | Helping Java Developers to improve their coding & collaboration skills so that they can meet great people & collaborate

100daysofcode 100daysofjava access advance-java agile algorithm arraylist article bangla-book becoming-expert biginteger book calculator checked checked-exceptions cloning code-readability code-review coding coding-convention collection-framework compact-strings completablefuture concatenation concurrency concurrentmodificationexception concurrentskiplistmap counting countingcollections critical-section daemon-thread data-race data-structure datetime day002 deliberate-practice deserialization design-pattern developers duration execute-around executors export fibonacci file file-copy fork/join-common-pool functional future-java-developers groupby hash-function hashmap history history-of-java how-java-performs-better how-java-works http-client image import inspiration io itext-pdf java java-10 java-11 java-17 java-8 java-9 java-developers java-performance java-programming java-thread java-thread-programming java11 java16 java8 lambda-expression learning learning-and-development linkedlist list local-type-inference localdatetime map methodology nio non-blockingio null-pointer-exception object-cloning optional packaging parallel pass-by-reference pass-by-value pdf performance prime-number programming project-loom race-condition readable-code record refactoring review scheduler scrum serialization serversocket simple-calculator socket software-development sorting source-code stack string string-pool stringbuilder swing thread threads tutorial unchecked vector virtual-thread volatile why-java zoneid