String vs StringBuffer vs StringBuilder
Published: 2023-04-08 14:54:53

Hi!

In a recent investigation and development of some application, I was in the middle of a doubt: it's better to use a `StringBuilder` in the place of a String Concatenation to print some value? Just like this:

```java
System.out.println(new StringBuilder()
  .append("Some value ")
  .append(anIntegerVariable));
```

So, in my searches I learned a lot and wanna to share my new knowledge about strings with you.

## What in fact is a String?

Perharps it appears to be primitives, or just an unnecessary class on Java API, the treatment Java does to it is correct.

1. A String is not a primitive
2. A String is a reference value, but is always constant

Let's clarify these two facts.
Primitive values are self-sufficient, independent and don't depend on another values to be defined. On the other side, complex values are composed by a set of some primitive values.
If you already have some contact with C lang, you noted that strings don't exists in it. In fact, what we have is a `char` array, and in the memory, is exactly what a string is.

So, we have some fixed range in the memory that will store our `char` array. Arrays are immutable by default, so it means that a String is immutable.

 By the way, Java will wrap this `char` array in a String class and treat it as a reference value.
*In more recent versions, Java gonna treat a string as a `byte` Array, and no more like a `char` Array*

To clarify this, let's see the very beginning code of `String` class to see what in fact it is:

```java
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence,
               Constable, ConstantDesc {

   // Stores the "string" inside the String object
    @Stable
    private final byte[] value;

    private final byte coder;

    private boolean hashIsZero; 

    @java.io.Serial
    private static final long serialVersionUID = -6849794470754667710L;

    
    static final boolean COMPACT_STRINGS;
/* ... */
}
```
So, the first fact was clarified.

The second fact is that a String is always a constant reference, no matters what happens in the program. It nevers get cleaned by the Garbage Collector, but that doesn't means that it represents a memory leak.

We should remember that, when our program runs, it gonna be executed inside the JVM, and the Operational System takes it as a process. Process usually have four sections:

1. Stack
2. Heap
3. Data
4. Text

When we hardcode some String into our code, every time it runs, the String will be ever present on the `Text` session of process, which stores all the program code.
To help in the concept, Rust gives a very explicit treatment to it. The language treat every string as having `'static` lifetime. It means that in the entire process life cycle, the string lives in it, even if it don't have no references to it.
So the second fact is clarified.

## Compiler Optimizations

The compilation process have a clear advantage over the direct interpretation. It can make some optimizations on the code ahead of time, reducing the overhead of Just-In-Time optimization.

In the case of strings, every time we declare a string literal, we are creating a `String` object. Let's see some examples:

```java

// one string object
"a string"

// two string objects
"two" + "strings"

// three string objects
"There are " + "three" + "strings"
```

So, a string concatenation don't help on this. In fact, it's worse: the JVM create the objects and after it, create more objects to represent the intermediate/final result of concatenation.

To prevent this behavior, the Java Compiler make some static analysis to convert this String concatenation to `StringBuffer` or `StringBuilder`.

## StringBuffer and StringBuilder

These two classes make possible a single String mutable object. So, we can append or insert some string or value inside these classes to craft a String and reduce overhead.

What's the difference between them?

The StringBuffer is suited for secure multi-threaded access.
The StringBuilder is suited for performant single-threaded access.

## So, what should I use?

* For manipulation of a String in a single context (print methods, concatenation on same scope), use just String/String concatenation;
* For manipulation of a String in multiple context on a single
thread (loops, concat results or logs of multiples methods on a single string, etc), use `StringBuilder`;
* For the former case, on multiple threads, use `StringBuffer`.