Quantcast

P^i

Your Online Tech Magazine

Sun05192013

Last update03:31:53 PM

Back You are here: Home More Programming and Web Programming The StringBuffer and StringBuilder Classes

The StringBuffer and StringBuilder Classes



The java.lang.StringBuffer and java.lang.StringBuilder classes should be used when you have to make a lot of modifications to strings of characters. As we discussed in the previous section, String objects are immutable, so if you choose to do a lot of manipulations with String objects, you will end up with a lot of abandoned String objects in the String pool. (Even in these days of gigabytes of RAM, it's not a good idea to waste precious memory on discarded String pool objects.) On the other hand, objects of type StringBuffer and StringBuilder can be modified over and over again without leaving behind a great effluence of discarded String objects.

A common use for StringBuffers and StringBuilders is file I/O when large, ever-changing streams of input are being handled by the program. In these cases, large blocks of characters are handled as units, and StringBuffer objects are the ideal way to handle a block of data, pass it on, and then reuse the same memory to handle the next block of data.

StringBuffer vs. StringBuilder

The StringBuilder class was added in Java 5. It has exactly the same API as the StringBuffer class, except StringBuilder is not thread safe. In other words, its methods are not synchronized. Sun recommends that you use StringBuilder instead of StringBuffer whenever possible because StringBuilder will run faster (and perhaps jump higher). So apart from synchronization, anything we say about StringBuilder's methods holds true for StringBuffer's methods, and vice versa.

Using StringBuilder and StringBuffer

In the previous section, we saw how to test your understanding of String immutability with code fragments like this:

String x = "abc";
x.concat("def");
System.out.println("x = " + x); // output is "x = abc"

Because no new assignment was made, the new String object created with the concat() method was abandoned instantly. We also saw examples like this:

String x = "abc";
x = x.concat("def");
System.out.println("x = " + x); // output is "x = abcdef"

We got a nice new String out of the deal, but the downside is that the old String "abc" has been lost in the String pool, thus wasting memory. If we were using a StringBuffer instead of a String, the code would look like this:

StringBuffer sb = new StringBuffer("abc");
sb.append("def");
System.out.println("sb = " + sb); // output is "sb = abcdef"

All of the StringBuffer methods we will discuss operate on the value of the StringBuffer object invoking the method. So a call to sb.append("def"); is actually appending "def" to itself (StringBuffer sb). In fact, these method calls can be chained to each other—for example,

StringBuilder sb = new StringBuilder("abc");
sb.append("def").reverse().insert(3, "---");
System.out.println( sb ); // output is "fed---cba"

Notice that in each of the previous two examples, there was a single call to new, concordantly in each example we weren't creating any extra objects. Each example needed only a single StringXxx object to execute.

Important Methods in the StringBuffer and StringBuilder Classes

The following method returns a StringXxx object with the argument's value appended to the value of the object that invoked the method.

public synchronized StringBuffer append(String s) As we've seen earlier, this method will update the value of the object that invoked the method, whether or not the return is assigned to a variable. This method will take many different arguments, including boolean, char, double, float, int, long, and others, but the most likely now will be a String argument—for example,

StringBuffer sb = new StringBuffer("set ");
sb.append("point");
System.out.println(sb); // output is "set point"
StringBuffer sb2 = new StringBuffer("pi = ");
sb2.append(3.14159f);
System.out.println(sb2); // output is "pi = 3.14159"

public StringBuilder delete(int start, int end) This method returns a StringBuilder object and updates the value of the StringBuilder object that invoked the method call. In both cases, a substring is removed from the original object. The starting index of the substring to be removed is defined by the first argument (which is zero-based), and the ending index of the substring to be removed is defined by the second argument (but it is one-based)! Study the following example carefully:

StringBuilder sb = new StringBuilder("0123456789");
System.out.println(sb.delete(4,6)); // output is "01236789"
 
Now will probably test your knowledge of the difference between String and StringBuffer objects. Because StringBuffer objects are changeable, the following code fragment will behave differently than a similar code fragment that uses String objects:

StringBuffer sb = new StringBuffer("abc");
sb.append("def");
System.out.println( sb );

In this case, the output will be: "abcdef"

public StringBuilder insert(int offset, String s) This method returns a StringBuilder object and updates the value of the StringBuilder object that invoked the method call. In both cases, the String passed in to the second argument is inserted into the original StringBuilder starting at the offset location represented by the first argument (the offset is zero-based). Again, other types of data can be passed in through the second argument (boolean, char, double, float, int, long, and so on), but the String argument is the one you're most likely to see:

StringBuilder sb = new StringBuilder("01234567");
sb.insert(4, "---");
System.out.println( sb ); // output is "0123---4567"

public synchronized StringBuffer reverse() This method returns StringBuffer object and updates the value of the StringBuffer object that invoked the method call. In both cases, the characters in the StringBuffer are reversed, the first character becoming the last, the second becoming the second to the last, and so on:

StringBuffer s = new StringBuffer("A man a plan a canal Panama");
sb.reverse();
System.out.println(sb); // output: "amanaP lanac a nalp a nam A"

public String toString() This method returns the value of the StringBuffer object that invoked the method call as a String:

StringBuffer sb = new StringBuffer("test string");
System.out.println( sb.toString() ); // output is "test string"

That's it for StringBuffers and StringBuilders. If you take only one thing away from this section, it's that unlike Strings, StringBuffer objects and StringBuilder objects can be changed.

A statement with chained methods has this general form:

result = method1().method2().method3();

In theory, any number of methods can be chained in this fashion, although typically you won't see more than three. Here's how to decipher these "handy Java shortcuts" when you encounter them:

1. Determine what the leftmost method call will return (let’s call it x).
2. Use x as the object invoking the second (from the left) method. If there are only two chained methods, the result of the second method call is the expression's result.
3. If there is a third method, the result of the second method call is used to invoke the third method, whose result is the expression’s result— for example,

String x = "abc";
String y = x.concat("def").toUpperCase().replace('C','x'); //chained methods
System.out.println("y = " + y); // result is "y = ABxDEF"

Let’s look at what happened. The literal def was concatenated to abc, creating a temporary, intermediate String (soon to be lost), with the value abcdef. The toUpperCase() method created a new (soon to be lost) temporary String with the value ABCDEF. The replace() method created a final String with the value ABxDEF, and referred y to it.








blog comments powered by Disqus