String, StringBuilder, and StringBuffer in Java
Tags: java, programming, algorithms, interviewquestions
Published: 2023-04-03 11:21:35

Hello!🖖🏼

This article will be about the String class that we frequently use in Java and its alternatives, StringBuilder and StringBuffer. There may be points that I missed, skipped, or inadvertently conveyed incorrectly. If you give me feedback via email in such a situation, I would be very happy.

Now, let’s get started🚀

---


## **1.String**
First, let’s look at the String class. As we all know, the String class is one of the complex data types in Java that represents character arrays. This class stores an array of characters and provides multiple functions for manipulating these characters. When we want to use it, we define it as shown below and assign a value.

```java
   String str= "Merhaba";
```

So far, there is no problem here. However, as we know, in Java, the **String** class is "**immutable**" meaning it cannot be changed. But of course, some of you might say, "*Oh no, I have changed and assigned many times and performed the operations I wanted!*"

This is where situations arise that prompted me to write this article.

In fact, when we manipulate a String variable, the value that the variable points to does not change 🙂. In such an operation, a new space is opened in the Heap, and the manipulated value is placed there, and our reference points to this new address.

```java
    String str = "Merhaba";
    str.concat("Dünya");
```

When we define as shown above and then perform the "**concat**" operation, as mentioned, a new space is created in memory, and our "**str**" variable now references the address where the "*MerhabaDünya*" variable is located.

So, a new space is being constantly opened in memory every time the variable is manipulated. And of course, this is not something we would want because it causes both performance and time loss. 🙂

![a](https://i.hizliresim.com/fqus7se.jpg)

&nbsp;
At this point, the **StringBuilder** class comes to our help.

## **2.StringBuilder**

The role of **StringBuilder** is also the same as **String**. It represents character strings. However, the difference from String is that it is a "**mutable**" or changeable class. Therefore, it is a better choice than the **String** class for efficient text manipulation.

For example, if we want to convert all the words in a text file to uppercase, the **StringBuilder** class can easily do this without recreating the entire text in memory (String was creating a new space in memory for this new value).

Or a very simple example like the one below.

```java
    StringBuilder sentence = new StringBuilder("This is a sentence.");
    sentence.append("Added word.");
    System.out.println(sentence.toString()); //This is a sentence.Added word.
```
However, there is an important drawback to this class that has not yet been mentioned, which is its lack of a thread-safe structure. If a process involving threads is to be used, the **StringBuilder** class is not suitable in this scenario. This limitation can be explained with the following code snippet:

```java
    StringBuilder sb = new StringBuilder();

    Thread t1 = new Thread(() -> {
        for(int i=0; i<10000; i++){
            sb.append("A");
        }
    });

    Thread t2 = new Thread(() -> {
        for(int i=0; i<10000; i++){
            sb.append("B");
        }
    });

    t1.start();
    t2.start();

    t1.join();
    t2.join();

    System.out.println(sb.toString());

```

In this example, two distinct threads, **t1** and **t2**, access the **StringBuilder** object concurrently and append the characters "A" and "B" 10,000 times each in a sequential manner. However, due to the lack of synchronization in the **StringBuilder** object, the resulting output is indeterminate and can yield varying results on each execution. In essence, a data race condition is introduced.

To address this issue, we can use the **StringBuffer** class instead.

## **3.StringBuffer**

I won't repeat the same information with StringBuffer here, if you have read this far, you can already guess that the only difference of this class is its "thread-safe" or synchronized structure. It has the same methods and logic as StringBuilder.

However, this great feature also brings some drawbacks. Its synchronized structure causes it to work slower than StringBuilder.

If we try to explain this with a small code snippet,


```java
    public class StringBufferVsStringBuilder {
        public static void main(String[] args) {
            int N = 1000000;
            long startTime, endTime, duration;

            // StringBuffer performance test
            StringBuffer buffer = new StringBuffer();
            startTime = System.nanoTime();
            for (int i = 0; i < N; i++) buffer.append("hello");
            
            endTime = System.nanoTime();
            duration = (endTime - startTime);
            System.out.println("Time taken by StringBuffer: " + duration + " nanoseconds");
            //Time taken by StringBuffer: 19494000 nanoseconds

            // StringBuilder performance test
            StringBuilder builder = new StringBuilder();
            startTime = System.nanoTime();
            for (int i = 0; i < N; i++) builder.append("hello");
            
            endTime = System.nanoTime();
            duration = (endTime - startTime);
            System.out.println("Time taken by StringBuilder: " + duration + " nanoseconds");
            //Time taken by StringBuilder: 17145000 nanoseconds
        }
    }
```
This code calculates the elapsed time for **StringBuilder** and **StringBuffer** to append the word "*hello*" one million times. When we run this code, we can easily observe that **StringBuffer** works slower due to its synchronized structure. We can make this difference more prominent by increasing the value of N.

As a summary, I am adding the features of both classes in the table below,

| Features | StringBuilder     | StringBuffer                       |
| :-------- | :------- | :-------------------------------- |
| **Thread-Safe**     | No | Yes |
| **Performance**      | Faster | Slower|
| **Memory Usage**        | Less | More |
| **Mutable**        | Yes | Yes|
&nbsp;



Finally,

- There is no harm in using the **String** class, but we should keep in mind that it is immutable, and every time we try to modify it, **a new memory space is created**.
- **StringBuilder**, on the other hand, performs all operations without the need for creating new memory spaces, but it may provide incorrect results in thread-containing applications since it does not have a synchronized structure.
- We can solve the problem of **StringBuilder** by using **StringBuffer**, which operates in a synchronized structure, but this class may cause some performance loss compared to **StringBuilder**.

If you have taken the time to read this far, thank you very much. If you notice any mistakes, please feel free to contact me via email.

⭐For the original article -> https://bayten.dev/posts/string-stringbuilder-and-stringbuffer-in-java/

Happy coding! 🎉
&nbsp;
&nbsp;

&nbsp;
&nbsp;
&nbsp;
&nbsp;
## References
- [https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html)
- [https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuffer.html](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuffer.html)
- [https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuilder.html](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuilder.html)
- [https://www.digitalocean.com/community/tutorials/string-vs-stringbuffer-vs-stringbuilder](https://www.digitalocean.com/community/tutorials/string-vs-stringbuffer-vs-stringbuilder)