String vs StringBuilder vs StringBuffer in Java

Strings are one of the inevitable topics in Java. The terms like StringBuilder, StringBuffer, and StringJoiner also have their own characteristics. This article will make you notice the fine line that differentiates all these terms from each other. Let’s see String vs StringBuilder vs StringBuffer in Java in detail.

What are Strings in Java?

A string is basically an object that denotes a sequence of characters. To print any number of characters on the console, we generally use String. The class Strings is prevalent among Java developers. Due to its immutability, a couple of utility classes, StringBuilder and StringBuffer, were built in Java.

To represent any sequence of characters in Java, we use Strings. We can either use the String literal or the NEW keyword to create it.

For example, String str = “Learn Java with FirstCode”; // using the String literal

String str = new String(“Learn Java with First Code”); // using NEW

Features of Strings in Java

1. Strings can perform many operations in the same way we perform arithmetic operations on integers and float. One such operation is concatenation using the ‘+’ operator. It is overloaded in String and internally uses the StringBuffer to achieve this.

2. Strings are immutable, and they work well when used in a multi-threaded environment.

3. There is no restriction in sharing it across functions due to the absence of data inconsistency concerns.
We can use the ‘new’ operator to create a string in the heap memory.

4. The + operator helps in concatenating two strings. StringBuffer is indirectly involved in performing this action. It is overloaded for a String.

5. Once a string is present inside double quotes, the JVM automatically looks for another string with the same value in the string pool. This results in returning the reference object when the same value is encountered. Else, a new string object is created and returns the reference. This saves a huge memory space as the same Different threads use Strings.

6. The character stream for UTF-16 encoding requires Strings.

7. It overrides two methods: equals() and hashcode(). Speaking of the former method, comparison can take place to find if they are equal or not. For this, the sequence of the characters must exactly be the same.

8. The other point to note in it are the equals() method is case sensitive; therefore, the equalsIgnoreCase() method is used to compare insensitive checks.

9. Excluding the “private int hash” field, all the other fields in String are final. Therefore, String is a final class. The “private int hash” field contains hashCode() function value which is calculated only when the method is called initially. Every time this method is called, the calculations will result in the same output. It might seem as though calculations are taking place each time, but it is actually cached in the hash field.

Limitations of String in Java

As we have already seen, String is immutable in Java. String manipulation like concatenation and finding the substring results in generating a new String as an output. Then, the String hat that was previously present is erased and added to the garbage collection.

These kinds of manipulations result in a large pile of garbage in a heap. To solve this issue, two mutable classes in Java, StringBuffer, and StringBuilder, are available. The in-built methods like append(), insert(), delete() and substring() help in achieving the desired result.

Java StringBuffer vs StringBuilder:

Initially, StringBuffer was the sole choice for String manipulations to take place in Java until Java 1.4. The public methods in StringBuffer were allowed to synchronize. This was its biggest disadvantage. Furthermore, the thread-safety was present only at the risk of performance.

To start from when they were introduced, StringBuffer was introduced in Java 1.0 and StringBuilder in Java 1.5. from this; it is obvious that StringBuffer had some drawbacks that led to the arrival of StringBuilder.
StringBuffer has some unwanted methods like substring, capacity, trimToSize, length, and many more. These methods are already present in String; therefore, they are not available in the StringBuilder class.

StringBuilder works fine in a single-threaded environment, but the thread safety is up to the mark. If you require thread-safety measures, StringBuffer will work better for you.

Sample program to demonstrate the StringBuffer class:

public class FirstCode{
public static void main(String args[])
StringBuffer buff = new StringBuffer("Learn Java ");
buff.append("with FirstCode");
System.out.println(buff)
}
}

Output:

Learn Java with FirstCode

Sample program to demonstrate the StringBuilder class:

public class FirstCode{
public static void main(String args[])
StringBuilder buil = new StringBuilder("Learn Java ");
buil.append("with FirstCode");
System.out.println(buil)
}
}

Output:

Learn Java with FirstCode

The above program might seem to produce the same kind of result. Let us now look into the performance of both the classes to understand their difference.

Sample program to denote the performance of StringBuffer and StringBuilder:

public class FirstCode{
public static void main(String args[]){
long beginTime = System.currentTimeMillis();
StringBuffer buff = new StringBuffer("Learn Java ");
for(i=0; i<10000; i++){
buff.append(“with FirstCode”);
}
System.out.println(“Time consumption of StringBuffer class: ” + (System.currentTimeMillis()- beginTime) + “ms”);
beginTime = System.currentTimeMillis();
StringBuilder buil = new StringBuilder(“Learn Java ”);
for(int i=0; i<10000; i++){
buil.append("with FirstCode");
}
System.out.println("Time consumption of StringBuilder class: "+ (System.currentTimeMillis() - beginTime) + "ms");
}
}

Output:

Time consumption of StringBuilder class: 16ms
Time consumption of StringBuffer class: 0ms

Explanation of the output:

The two classes, StringBuilder and StringBuffer, produce the same output. The first String, “Learn Java” is appended to “with FirstCode” using the buff.append and buil.append methods. The difference here takes place in the time that is consumed to produce the result and thread-safety.

StringBuffer provides thread safety whereas, StringBuilder does not guarantee it. The presence of synchronized methods in StringBuffer controls the thread and provides access to one at a time. This is absent in the case of a StringBuilder class.

Mutability in Java

As mentioned earlier, Strings are immutable whereas, StringBuffer and StringBuilder are mutable. This means we do not have permission to change the Strings when we use them in the String class. But we can change them when we use them in the StringBuffer or StringBuilder class.

Sample program to show mutability in Strings:

public class FirstCode{
public static void StrCon(String s1)
{
s1 = s1 + “Java”;
}
public static void StrBuffCon(StringBuffer s2)
{
s2.append(“Java”);
}
public static void StrBuilCon(StringBuilder s3)
{
s3.append(“Java”);
}

public static void main(String args[]){
String s1 = “Learn”;
StrCon(s1);
System.out.println(“The string is: ”+s1);

StringBuffer s2 = new StringBuffer(“Learn”);
StrBuffCon(s2);
System.out.println(“The string is: ”+s2);

StringBuilder s3 = new StringBuilder(“Learn”);
StrBuilCon(s3);
System.out.println(“The string is: ”+s3);

}
}

Output:

The String is: Learn
The String is: Learn Java
The String is: Learn Java

Code explanation:

There are three functions used in the program above: StrCon, StrBuffCon and StrBuilCon. In the first function, the string “Learn” is passed. Using the + operator, the string “Java” is concatenated(s1 = s1 + “Java”). But in the output, there is no change occurred. This is because s1 in main() refers to “Java” and s1 refers to a different object.

In the function StrBuffCon and StrBuilCon, the output is mutable. This is achieved by using the mutable() function. As there are no extra needs to be satisfied, StringBuilder does not slow down the processing speed.

The appropriate option in certain situations:

As the above-explained methods provide the desired output, you might be perplexed about when to use a particular method.

  • In situations when a string would stay the same throughout a program, the String class can be used as it is changeless.
  • Whereas, when a String can change by getting the changes from a single String, it is good to use StringBuilder.
  • On the other hand, when the String can change by getting changes from various Strings, a StringBuffer works well. As it provides synchronization, the security of the String is assured.

Looking at the performance:

StringBuilder performs faster than StringBuffer. This is because StringBuilder does not support synchronization.

Change between the sorts of Strings in Java:

In some cases, a need for change over string object of classes like String, StringBuffer and StringBuilder is required. The following content provides you with the procedures to do so.

a. From StringBuffer and StringBuilder to String:

The toString() method present in the StringBuffer and StringBuilder classes executes this transformation. In the following sample program, the toString() technique.

Sample program to execute StringBuffer and StringBuilder to String:

public class FirstCode{
public static void main(String args[]){
StringBuffer buff = new StringBuffer(First”);
String str = buff.toString();
System.out.println(str);
String str2 = buff.toString();
buff.append(“Code”);
System.out.println(buff);
System.out.println(str);
}
}

b. From StringBuffer to StringBuilder or vice versa:

There is no direct method to achieve this state. The String class object serves this purpose. To begin with, we must change the StringBuffer/StringBuilder object String utilization toString() technique. Later we can change the String to StringBuilder/StringBuffer utilizing constructors. You can clearly understand this process by looking at the sample program below:

Sample program to change StringBuffer to StringBuilder and vice versa:

public class FirstCode{
public static void main(){
StringBuffer buff = new StringBuffer(First”);
String str = buff.toString();
StringBuilder buil = new SringBuilder(str);
System.out.println(buil);
}
}

c. From String to StringBuffer and StringBuilder:

We can directly pass a String class to StringBuffer and StringBuilder class constructors. The unchanging property of the String class in Java makes it easier to edit. This is made by changing it to changing it into StringBuffer or StringBuilder class objects.

Sample program to demonstrate the change of String to StringBuffer and StringBuilder:

public class FirstCode{
public static void main(String args[]){
String str = “First”;
StringBuffer buff = new StringBuffer(str);
buff.reverse();
System.out.println(buff);
StringBuilder buil= new StringBuilder(str);
buil.append(“Code”);
}
}

Tabulating the Differences between StringBuffer and StringBuilder:

No. StringBuffer StringBuilder
1 It is synchronized. Therefore, it does not allow more than one thread to call the StringBuffer method simultaneously. In simple terms, it is thread safe. 

 

It is non-synchronized. 
2 Introduced in Java 1.0

 

Introduced in Java 1.5
3 Multiple threads are involved

 

Single threaded environment
4 Comparatively less efficient

 

Comparatively more efficient
5 Syntax: StringBuffer var = newStringBuffer(str);

 

Syntax: StringBuilder var = new StringBuilder(str);

StringJoiner in Java:

As we have seen the major differences between the StringBuffer and the StringBuilder, now let us look into what is a StringJoiner. It is a new final class that was added to the Java.util package. We can use delimiters to separate the sequence of characters. These delimiters can either be a comma(,), hyphen(-), and so on.
StringJoiner Constructors:

Constructor  Description
Public StringJoiner(CharSequencedelimiter) It allows to construct a StringJoiner without characters, prefix, suffix and a copy of supplied delimiter. When the delimiter is null, it throws the NullPointerException.

 

Public StringJoiner(CharSequencedemilter,CharSequence prefix,CharSequence suffix) It allows to construct a StringJoiner without characters and just using the copies of supplied prefix, suffix and delimiter. When a prefix, suffix, or delimiter is null, it throws an exception.

Java StringJoiner Methods:

Method Description
Public StringJoiner add(CharSequence newElement) A copy of the CharSequence’s value is added as the suffix to the StringJoiner’s value. If the newElement is null, the string “null” is added.

 

Public StringJoiner merge(StringJoiner other) The content given in the StringJoiner is added without prefix and suffix as the next element if it is non-empty. In the other case, if it is empty, the call does not create an effect.

 

Public int length() The string representation’s length of StringJoiner is returned.

 

Public StringJoiner setEmptyValue(CharSequence emptyValue) The character sequence that can be used in determining the string representation of the StringJoiner is set with this method. This is done when it is empty before adding any elements.

 

Sample program for Java StringJoiner:

import java.util.StringJoiner;
public class FirstCode{
public static void main(String args[]){
StringJoiner joinWords = new StringJoiner(",","[","]");
joinWords.add("Learn");
joinWords.add("Java");
joinWords.add("with");
joinWords.add("FirstCode");
}
}

Output:

[Learn, Java, with, FirstCode]

Sample program to merge two Java StringJoiners:

import java.util.StringJoiner;
public class FirstCode{
public static void main(String args[]){
StringJoiner joinWords = new StringJoiner(",","[","]"); // here, comma and square bracket are used as delimiters
joinWords.add("Learn");
joinWords.add("Java");

StringJoiner StringJoiner joinWords2 = new StringJoiner(":","[","]"); // here, colon and square bracket are used as delimiters

joinWords.add("with");
joinWords.add("FirstCode");

StringJoiner merge = joinWords.merge(joinWords2);
System.out.println(merge);
}
}

Output:

[Learn, Java, with:FirstCode]

Sample program to display Java StringJoiner Methods:

import java.util.StringJoiner;
public class FirstCode{
public static void main(String args[]){
StringJoiner joinWords = new StringJoiner(","); //here, the comma is the delimiter

System.out.println(joinWords); // this prints nothing as it is empty
joinNames.setEmptyValue("This is empty");
System.out.println(joinWords); //setting a default value
joinWords.add("Learn Java");
joinWords.add("with FirstCode");
System.out.println(joinWords);

int length = joinWords.length();
System.out.println("The Length is:" +length); // this returns the StringJoiner's length

String s = joinWordstoString();
System.out.println(s); // this returns StringJoiner as String type
char ch = str.ChatAt(6);
System.out.println("The character index at 6th position is:" +ch);

joinWords.add("Easily");
System.out.println(joinWords); // adding another element

int newLength = joinNames.length();
System.out.println("The Current Length is= "+newLength);
}
}

Output:

This is empty
Learn Java, with FirstCode
The length is: 24
Learn Java, with FirstCode
The character index at 6th position is: J
Learn Java, with FirstCode, Easily
The Current Length is: 31

When to pick Java StringJoiner over StringBuilder:

StringJoiner is the perfect choice when you need to join various Strings in a Stream. We can also add delimiters, prefixes and constructors using the add(String str) strategy.

For example, let us take three strings: “Alaska”, “Canada” and “Paris”. Let us now join them as “[Alaska:Canada:Paris]” using StringJoiner.

Sample program implementing StringJoiner:

public class FirstCode{
public static void main(String args[]){
String str[] = {“Alaska”, “Canada”, “Paris”};
Stringjoiner strjo = new StringJoiner{“:”, “[”, “]”};
strjo.add(“Alaska”).add(“Canada”).add(“Paris”);
String finalString = strjo.toString();
System.out.println(finalString);
StringBuilder buil = new StringBuilder();
buil.append(“[”);
if(str.length>0){
buil.append(str[0]);
for(int i = 1; i<str.length; i++){
buil.append(“:”).append(str[i]);
}
}
buil.append(“]”);
String finalString2 = buil.toString();
System.out.println(finalString2);
}
}

Output:

[Alaska:Canada:Paris]
[Alaska:Canada:Paris]

Conclusion

Now, you might have a clear understanding of String, StringBuffer, StringBuilder, and StringJoiner in Java. Here is a simple table to depict the differences between Java String vs StringBuffer vs StringBuilder:

Parameter String StringBuffer StringBuilder
Storage String Pool Heap Heap
Thread Safety Not used in threaded environment Multi-threaded environment Single-threaded environment
Performance Slow Slower than StringBuilder but faster than String Faster than StringBuffer
Mutability Immutable Mutable Mutable
Syntax String var = “FirstCode”;

 

String var = new String(“FirstCode”);

StringBuffer var = new StringBuffer(“FirstCode”); StringBuilder var = new StringBuilder(“FirstCode”);

 

Leave a Reply

Your email address will not be published. Required fields are marked *