Architecture & DesignExploring the Peer Classes of Java String: Java StringBuilder and Java StringBuffer

Exploring the Peer Classes of Java String: Java StringBuilder and Java StringBuffer

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Java provides three elaborate schemes for handling strings directly under the aegis of the Object class. A class that represents immutable sequence of characters called the String, the StringBuffer class that represents thread-safe mutable sequence of characters and the StringBuilder, representing a mutable sequence of characters without the guarantee of synchronization. These classes define many methods within it, apart from providing a base for deep hierarchical lineage. This article tries to provide the sense behind their existence with an impetus on their usage in brief.

Overview

Before delving into the string classes, let’s glimpse into their association with other interfaces defined in the Java API library.

public final class String
extends Object
implements Serializable, Comparable<String>,
   CharSequence

public final class StringBuffer
extends Object
implements Serializable, CharSequence

public final class StringBuilder
extends Object
implements Serializable, CharSequence

The String class implements three interfaces viz. Serializable, Comparable and CharSequence. And the StringBuffer and StringBuilder classes implements  Serializable and CharSequence. They are all final classes, means they cannot be inherited or sub-classed. A significant power of these classes are derived from the implementation of interfaces. They may be briefly accounted as follows.

Serializable

The classes that implement this interface serve to identify that the state of the class follows the semantics of serialization or deserialization in the course of the existence of its objects.

The following articles provides more details on the concept of serialization:

CharSequence

This interface provides the framework for a uniform, read-only access to the sequence of different kinds of char values, such as represented by Basic Multilingual Plane (BMP) or surrogate. The changed standard of unicode encoding allows characters to be representation beyond 16-bits. The BMP therefore represents the char values from U+0000 to U+FFFF. Because Java uses UTF-16 based, char arrays with String and StringBuffers the supplementary characters are represented by a pair of char values ranging from uD800 to uDBFF and uDC00 to uDFFF, called the high surrogates and low surrogates, respectively. Thus, a char value includes both BMP and the surrogate code points of UTF-16 encoding.

Interested readers may find the article “How to Create a Multilingual JasperReport” interesting with respect to Unicode character handling.

The methods declared within the interface adhere to the contract of uniformity. But, the result of comparison between objects that implement CharSequence is typically undefined because objects defined by different class do not guarantee the capability of testing their equality with another instance. They may not be uniform under the criteria of an encoding scheme. This specifically is the reason why arbitrary CharSequence should not be used as an element of set or keys in a map.

Comparable

This interface imposes the principle of natural ordering of the items associated with the class. The only method, compareTo(), declared by the interface acts on this principle of natural ordering that is consistent with equals. The use of the Comparable interface with the String class gives it the ability to examine individual characters of the sequence, especially for string comparison and other relevant operations. Refer to this article “Using Java Comparator” for a more comprehensive view.

Apart from the interfaces associated with StringBuffer and StringBuilder, there is another subtle interface associated with these two classes through the undocumented (Java API Docs) abstract class, called AbstractStringBuilder. This interface is called Appendable.

Appendable

This interface is typically implemented by a class that intends to receive formatted output. The appended characters must adhere to the UTF-16 encoding scheme.

The String Class

A String in Java is neither a primitive nor an array of characters. It is basically a class the represents a sequence of character constants. However, the interesting fact is that it behaves like a primitive and, most of the time while programming, we deal with it in the like manner. We can declare a String variable, create an array of String, or use assignments almost like the primitive types. The fact is that String is so common in Java programming that the behavior is not warranted but intended to be like the primitive type.

A String constant declared in double quotes such as:

System.out.println("Hello String");

It is actually a String object, though it may not seem so. A Stringobject may be constructed in many ways, such as:

String str1="Hello String";

Concatenate two or more strings:

String str2="Hello" +" String";
String str3=str2+"."

The equality of size of the string measured by the method called length() is defined in the String class.

The String class is convenient for most string handling operations such as comparing two strings, concatenating two string, searching for a substring, or changing the case of letters in the string apart from using the string object like a primitive data type. But the problem is that, when we create a string object, we also vouch for its immutability. That is, the characters that comprise the string cannot be changed. This, however, is not a shortcoming but an inconvenience of the String class.

Therefore, Java supplies two more classes called StringBuffer and StringBuilder that enable us to create modifiable strings. These two classes lay no restriction on creating a string that is alterable even after creation.

StringBuffer and StringBuilder

The StringBuffer and StringBuilder classes are very similar in their functionality and also have some of the same methods defined within them. In contrast to String’s fixed length immutable character sequence, these two classes represent grow-able and at the same time editable character sequence. We always can append or insert a substring into the already existing string represented by these classes. Room will be allocated automatically; in fact, these classes maintain certain pre-allocated characters that actually are needed as a form of proactive expansion.

The reason for the existence of three type string classes may be due to the change of ideas during the course of the development of Java API library; nonetheless, they serve their purpose with a little confusion at the beginning of understanding. This is strange because both the StringBuffer and the StringBuilder classes have similar capabilities, yet very are distinctly derived from their parent classes.

To get a better understanding, let’s compare the three classes and when to use them.

In Java programming, we often refer to one String object for multiple variables, apart from creating a immutable string. This type of reference is very conducive for optimization by the Java compiler because the object does change. This type of scenario fits the use of the String object. In cases where we require frequent string operations, such as concatenation or other string modification, it is more efficient to use StringBuilder object.

But, StringBuilder is not threadsafe. Therefore, if we need multiple threads to access the same dynamic string information, we must use StringBuffer. The StringBuffer and StringBuilder, though, have identical capabilities, yet they are distinct only in the sense that StringBuffer is threadsafe whereas StringBuilder is not. If the criteria of choice between is on efficiency, StringBuilder is the on to be picked.

Here is an example code to illustrate the efficiency between StringBuilder and StringBuffer.

package org.mano.example;

public class Benchmark {

   public static void main(String[] args) {
      System.out.println("StringBuffer:");
      testStringBuffer();
      System.out.println("StringBuilder:");
      testStringBuilder();
   }

   public static void testStringBuffer() {

      StringBuffer stringBuffer = new StringBuffer();
      long startTime = System.currentTimeMillis();
      for (int i = 0; i < 100000; i++)
         stringBuffer.append(i);
      long endTime = System.currentTimeMillis();
      System.out.println("Elapsed time=" +
         (endTime - startTime)+"ms");
   }

   public static void testStringBuilder() {
      StringBuilder stringBuilder = new StringBuilder();
      long startTime = System.currentTimeMillis();
      for (int i = 0; i < 100000; i++)
         stringBuilder.append(i);
      long endTime = System.currentTimeMillis();
      System.out.println("Elapsed time=" +
         (endTime - startTime)+"ms");
   }

}

Output:

StringBuffer:
Elapsed time=32ms
StringBuilder:
Elapsed time=11ms

Here, we do not go into the details of the methods supplied by these classes. Interested readers may peruse the Java API Documentation in great detail.

Conclusion

StringBuilder is more a spontaneous design for StringBuffer and should be used more often in association with the String object, especially due to its efficiency. StringBuffer, on the other hand, should be used reluctantly, and only when there is a chance of string buffer being used by multiple thread. So, in a nutshell, we may conclude as follows:

StringBuffer + (Single thread) = StringBuilder;
StringBuilder + (multiple thread) = StringBuffer;

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories