The StringBuilder ClassJ8 Home « The StringBuilder Class

In our last lesson we learnt all about the predefined String object and some of the multitude of methods available to manipulate our strings. As we saw in that lesson string immutability can improve efficiency, the downside is we can also have a lot of strings that get lost in the string constant pool, when we reassign or discard our reference variables.

Luckily for us Java comes with the predefined StringBuffer and StringBuilder classes which we can use to modify strings without the pros and cons of immutability. So when you are doing a lot of string manipulation these are the classes to use. The StringBuilder class was introduced in Java as an alternative to the older StringBuffer class. Both these classes have the same API apart from the StringBuffer class being thread safe and having synchronized methods. For most situations when manipulating strings, thread safety isn't an issue and so the StringBuilder class is the better option for efficiency. For this reason we will focus on the StringBuilder class in this lesson although the same principles learnt here can be applied to the StringBuffer class when thread safety is a requirement. We will talk a lot more about thread safety and synchronization in the Concurrency section.

String Concatenation Top

We saw in the last lesson how we can use the String class concat() method to concatenate a string literal to an existing string. The resulting string never changed though, unless we reassign the reference variable to a new string. During the reassignment, the old string is lost in the string constant pool, which is inefficient. The StringBuilder class offers us an alternative concatenation method called append(). To see the difference in the two approaches to string concatenation we will write a test class:


package info.java8;
/*
  The append() method
*/
public class TestAppend {
    public static void main(String[] args) {
        String str1 = new String("java");
        System.out.println("str1: " + str1.concat("Tutor"));
        System.out.println("str1: " + str1); // Still "java" as String objects immutable
        String str2 = new String("java");
        str2 = str2.concat("Tutor"); // Reassign so "java" now lost in string constant pool
        System.out.println("str2: " + str2);
        StringBuilder str3 = new StringBuilder("java");
        System.out.println("str3: " + str3.append("Tutor"));
        System.out.println("str3: " + str3); // "javaTutor" as StringBuilder objects are not immutable
    }
}

Save, compile and run the file in directory   c:\_APIContents in the usual way.

run sb append()

The screenshot above shows the string values held by reference variables str1, str2 and str3 after running the concat() method on str1 and str2 and the append() method on str3. We can see that the only way to change a String objects string value is through reassignment which is ineffiecient. With the StringBuilder class however we don't have this problem and can happily modify strings of this class as they are not immutable. This means we are not discarding strings within the string constant pool when using the StringBuilder class append() method and so don't have this overhead. When doing a lot of string concatenation this can lead to huge improvements on efficiency and thus performance, so make the StringBuilder class append() method, your method of choice in these situations. Also with the StringBuilder class append() method, the argument to the method can be many different types, but I'll leave that as an exercise for you to look at.

String Manipulation Top

There are several classes in the String and StringBuilder classes which allow us to manipulate strings. Here we will look at the substring method which is available in both these classes and allows us to extract a sequence of characters from a string. This method has two signatures and we will look at the second of these here where we supply an inclusive start and exclusive end index for the substring we are interested in:


package info.java8;
/*
  The substring() method
*/
public class TestSubstring {
    public static void main(String[] args) {
        String str1 = new String("tictactoe");
        System.out.println("str1: " + str1.substring(3,6));
        System.out.println("str1: " + str1); // Still "tictactoe" as String objects immutable
        String str2 = new String("tictactoe");
        str2 = str2.substring(3,6)); // Reassign so "tictactoe" now lost in string constant pool
        System.out.println("str2: " + str2);
        StringBuilder str3 = new StringBuilder("tictactoe");
        System.out.println("str3: " + str3.substring(3,6));
        System.out.println("str3: " + str3); // Still "tictactoe" as returned String object immutable
    }
}

Save, compile and run the file in directory   c:\_APIContents in the usual way.

run substring()

The screenshot above shows the string values held by reference variables str1, str2 and str3 after running the String class substring() method on str1 and str2 and the StringBuilder class substring() method on str3. In all cases the returned type is a String which is immutable so for this method the results are the same regardless of the input class.

String Replacement Top

We saw in the last lesson how we can use the String class replace() method to replace any occurrences of the first argument char value with occurrences of the second argument char value. The resulting string would never changed though, unless we reassign the reference variable to a new string. During the reassignment, the old string is lost in the string constant pool, which is inefficient. The StringBuilder class also offers us a method also called replace() which will replace sequences of characters. To see the difference in the two methods we will write a test class:


package info.java8;
/*
  The replace() method
*/
public class TestSBReplace {
    public static void main(String[] args) {
        String str1 = new String("mississippi");
        System.out.println("str1: " + str1.replace("i", "I"));
        System.out.println("str1: " + str1); // Still "mississippi" as String objects immutable
        String str2 = new String("mississippi");
        str2 = str1.replace("i", "I"); // Reassign so "mississippi" now lost in string constant pool
        System.out.println("str2: " + str2);
        StringBuilder str3 = new StringBuilder("mississippi");
        System.out.println("str3: " + str3.replace(0, 10, "I"));
        System.out.println("str3: " + str3); // "Ii" as StringBuilder objects are mutable
        StringBuilder str4 = new StringBuilder("mississippi");
        System.out.println("str4: " + str4.replace(1, 4, "ISS")); // Sequences of chars can be replaced
    }
}

Save, compile and run the file in directory   c:\_APIContents in the usual way.

run sb replace()

The screenshot above shows the string values held by reference variables str1, str2, str3 and str4 after running the String class replace() method on str1 and str2 and the StringBuilder class replace() method on str3 and str4. We can see that the only way to replace a String objects string value is through reassignment which is ineffiecient. With the StringBuilder class however we don't have this problem and can happily replace strings of this class as they are not immutable. This means we are not discarding strings within the string constant pool when using the StringBuilder class replace() method and so don't have this overhead. The other thing to be aware of is how the the replace() method works differently for the String and StringBuilder classes. Also with the StringBuilder class replace() method, the last argument to the method can be many different types.

String Summary Top

The last two chapters just skim the surface of how we can manipulate strings in Java and you really need to look at the Oracle online documentation for the JavaTM 2 Platform Standard Edition 5.0 API Specification for the full picture of these classes. Hopefully you have more of an understanding of how strings work in Java and are happy with the terminology used.

To summarize these chapters we looked at how String objects are immutable and can never be changed. This is done for efficiency purposes and whenever we create a String object it is put into the string constant pool. Depending on how the String object was instantiated and what currently resides in the string constant pool, 0, 1 or 2 String objects are created on instantiation. We can reassign a new string value to a reference variable but we must remember that the old string is still in the string constant pool and unless referenced elsewhere is now lost. When doing a lot of string manipulation this can lead to a lot of lost strings and ineffieciency.

Luckily for us the Java API also provides us with the StringBuffer and StringBuilder classes to work with strings and objects from both of these classes are mutable. So when you are doing a lot of string manipulation these are the classes to use. The StringBuilder class was introduced in Java as an alternative to the older StringBuffer class. Both these classes have the same API apart from the StringBuffer class being thread safe and having synchronized methods. For most situations when manipulating strings, thread safety isn't an issue and so the StringBuilder class is the better option for efficiency. Both these classes have methods that have the same names as ones in the String class and these methods may or may not work the same dependany upon the parameter lists and return types. There are also methods in these classes not available in the String class and vice versa. As you work with these classes you will get a feel for what to use and when.

Lesson 2 Complete

We learnt about the predefined StringBuilder object and some of the methods available for use with this class.

What's Next?

In the next lesson we take a closer look at how Java stores predefined classes into namespaces, which Java calls packages, and how we can import these packages into our programs.