Java 11 Developer Certification - StringBuilder
October 11, 2020
What we are covering in this lesson
- What is StringBuilder
- StringBuilder constructors
- StringBuilder Comparisions
- StringBuilder methods
- StringBuffer
What is StringBuilder
As now we all know that Strings are immutable, objects created using StringBuilder are mutable. We should always use Strings and only opt for StringBuilder if it offers performance benefits or simpler code. For example, suppose we have a loop which would run for 100 or more iterations and concatenate string in each iteration. For each iteration, there will be new String object created if we use normal Strings. So instead, we can use StringBuilder here.
StringBuilder has a capacity which is the number of character spaces allocated to it. Capacity is automatically extended as additions are made to the StringBuilder object.
StringBuilder constructors
There are four constructors that we can use to create StringBuilder objects.
StringBuilder()
- Empty StringBuilder object with an initial capacity of 16 (all empty elements).StringBuilder(CharSequence cs)
- object created with capacity equal to cs.length() + 16 empty trailing elements.StringBuilder(int capacity)
- Empty object created with mentioned capacity.StringBuilder(String s)
- same logic as in case of charSequence, capacity is s.length() + 16 empty trailing elements.
package maxCode.online.String;
public class StringBuilderExample {
public static void main(String[] args) {
// creates empty builder with initial capacity 16
StringBuilder sb = new StringBuilder();
System.out.println("Empty sb.length = " + sb.length());
System.out.println("Empty sb.capacity = " + sb.capacity());
// adds character string at beginning
sb.append("MaxCode");
System.out.println("sb.length after append = " + sb.length());
System.out.println("sb.capacity after append = " + sb.capacity());
StringBuilder sb2 = new StringBuilder("MaxCode");
System.out.println("sb2.length = " + sb2.length());
System.out.println("sb2.capacity (length + 16) = " + sb2.capacity());
StringBuilder sb3 = new StringBuilder();
sb3.append("abcdefghijklmnopqrstuvwxyz");
System.out.println("sb3.length = " + sb3.length());
System.out.println("sb3.capacity = " + sb3.capacity());
// Initial capacity 26
StringBuilder sb4 = new StringBuilder(26);
System.out.println("sb4.length = " + sb4.length());
System.out.println("sb4.capacity = " + sb4.capacity());
sb4.append("abcdefghijklmnopqrstuvwxyz");
System.out.println("sb4.length = " + sb4.length());
System.out.println("sb4.capacity = " + sb4.capacity());
sb4.append("aa");
System.out.println("sb4.length after appending 'aa' = " + sb4.length());
System.out.println("sb4.capacity after appending 'aa' = " + sb4.capacity());
}
}
Output
Empty sb.length = 0
Empty sb.capacity = 16
sb.length after append = 7
sb.capacity after append = 16
sb2.length = 7
sb2.capacity (length + 16) = 23
sb3.length = 26
sb3.capacity = 34
sb4.length = 0
sb4.capacity = 26
sb4.length = 26
sb4.capacity = 26
sb4.length after appending 'aa' = 28
sb4.capacity after appending 'aa' = 54
Most of the output values are self explanatory. The last output of 54
shows that the new capacity is equal to the length (28) + initial capacity (26) since we have explicity mentioned the initial capacity in constructor.
StringBuilder Comparisions
As we know about the compareTo
method in String, similar method has been introduced for StringBuilder as well in Java 11. The output is exactly the same as it would have been on string objects. We can also invoke ==
and .equals
on the StringBuilder objects.
package maxCode.online.String;
public class StringBuilderComparision {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("MaxCode");
StringBuilder sb2 = new StringBuilder("MaxCode");
// == comparator (compares references)
System.out.println("(sb == sb2) = " + (sb == sb2));
// .equals operator from java.lang.Object
System.out.println("(sb.equals(sb2)) = " + (sb.equals(sb2)));
// .compareTo method defined on StringBuilder Object
System.out.println("(sb.compareTo(sb2)) = " + (sb.compareTo(sb2))); //introduced in Java 11
// .equals used to compare String Values of StringBuilder objects
System.out.println("(sb.toString().equals(sb2.toString()) = " +
sb.toString().equals(sb2.toString()));
// == used to compare String Values of StringBuilder objects
System.out.println("(sb.toString() == sb2.toString()) = " +
(sb.toString() == sb2.toString()));
}
}
Output
(sb == sb2) = false
(sb.equals(sb2)) = false
0
(sb.toString().equals(sb2.toString()) = true
(sb.toString() == sb2.toString()) = false
StringBuilder methods
append and insert method
The append methods add data to the end of the current value of the StringBuilder, expanding capacity, if needed. The insert methods insert the specified data into the StringBuilder value at the specified starting index. There are many variations of append and insert methods and you can find those in the commented lines in the below code. The important thing to remember here is that in StringBuilder append and insert methods, the value of the object changes directly, unlike string concat methods which only return the new value without changing the object.
package maxCode.online.String;
public class StringBuilderAppendInsert {
public static void main(String[] args) {
/*
StringBuilder append(boolean b)
StringBuilder append(char c)
StringBuilder append(char[] str)
StringBuilder append(char[] str, int offset, int len)
StringBuilder append(double d)
StringBuilder append(float f)
StringBuilder append(int i)
StringBuilder append(long lng)
StringBuilder append(CharSequence s)
StringBuilder append(CharSequence s, int start, int end)
StringBuilder append(Object obj)
StringBuilder append(String str)
StringBuilder append(StringBuffer sb)
StringBuilder appendCodePoint(int codePoint)
*/
StringBuilder sb = new StringBuilder(100);
sb.append("Hello ")
.append(new char[]{'W', 'o', 'r', 'l', 'd'})
.append(',')
.append((Object) " My ")
.append("NewNumber ", 3, 9) //Number
.append(" is ")
.appendCodePoint(97)
.append(" float with the value of: ")
.append(123.45f);
System.out.println("sb = " + sb);
System.out.println("sb.length() = " + sb.length());
System.out.println("sb.capacity() = " + sb.capacity());
/*
StringBuilder insert(int offset, boolean b)
StringBuilder insert(int offset, char c)
StringBuilder insert(int offset, char[] str)
StringBuilder insert(int offset, char[] str, int offset, int len)
StringBuilder insert(int offset, double d)
StringBuilder insert(int offset, float f)
StringBuilder insert(int offset, int i)
StringBuilder insert(int offset, long lng)
StringBuilder insert(int dstoffset, CharSequence s)
StringBuilder insert(int dstoffset, CharSequence s, int start, int end)
StringBuilder insert(int offset, Object obj)
StringBuilder insert(int offset, String str)
*/
StringBuilder sb2 = new StringBuilder(100);
sb2.insert(0, "Hello , is a float with the value of ")
.insert(6, new char[]{'W', 'o', 'r', 'l', 'd'})
.insert(13, (Object) "My ")
.insert(16, "NewNumber ", 3, 10) //Number
.insert(sb2.length(), 123.45f);
System.out.println("sb2 = " + sb);
System.out.println("sb2.length() = " + sb.length());
System.out.println("sb2.capacity() = " + sb.capacity());
}
}
Output
sb = Hello World, My Number is a float with the value of: 123.45
sb.length() = 59
sb.capacity() = 100
sb2 = Hello World, My Number is a float with the value of: 123.45
sb2.length() = 59
sb2.capacity() = 100
delete, reverse and substring methods
deleteCharAt()
is used to delete a specific character at a specific index.
indexOf()
will return the index for any specific character.
delete()
will delete everything after the specified index value.
reverse()
as the name suggests, reverses the value.
Now if we assign the reverse result to a different variable, the original variable value also gets reversed and the same is assigned to the new one, effectively creates a reference to the same text.
This is why we get (rb == ss) = true
and the append actually results in change in both the variable values as seen in the output.
package maxCode.online.String;
public class StringBuilderManipulation {
public static void main(String[] args) {
// Create and Initialize a StringBuilder Object
StringBuilder sb = new StringBuilder("Hello World, How are you?");
System.out.println("Original Value in sb = " + sb);
// Delete the comma from the string
System.out.println("sb.deleteCharAt(sb.indexOf(\",\") = " +
sb.deleteCharAt(sb.indexOf(",")));
// Delete everything after where the comma used to be
System.out.println("sb.delete(11,sb.length()) = " +
sb.delete(11, sb.length()));
// reverse the entire string
sb.reverse();
System.out.println("sb after reverse() method called = " + sb);
// Assigning reversed value to a different StringBuilder variable
StringBuilder rb = sb.reverse();
System.out.println("(rb == ss) = " + (rb == sb));
// Now you have two StringBuilder references pointing to the same mutable text
sb.append(" How are you?");
System.out.println("sb = " + sb);
System.out.println("rb = " + rb);
String subString = sb.substring(0, 5);
System.out.println("subString = " + subString);
System.out.println(sb);
}
}
Output
Original Value in sb = Hello World, How are you?
sb.deleteCharAt(sb.indexOf(",") = Hello World How are you?
sb.delete(11,sb.length()) = Hello World
sb after reverse() method called = dlroW olleH
(rb == ss) = true
sb = Hello World How are you?
rb = Hello World How are you?
subString = Hello
Hello World How are you?
One of the very few methods which doesnt return a self reference is the substring()
method. It always returns a new string and not a self reference, so calling substring on the variable wont change its value. As we can see in the output, substring returns the value and the original StringBuffer remains unchanged.
trimToSize
The javadoc for trimToSize describes the method’s purpose as “Attempts to reduce storage used for the character sequence”. So it only attempts to compact the capacity of the stringbuilder object and does not trim the whitespaces.
To remove whitespace, we have the strip()
method introduced in Java 11. So we will have to convert the stringbuilder object to string and then use strip method on it.
package maxCode.online.String;
public class StringBuilderTrimToSize {
public static void main(String[] args) {
StringBuilder builder = new StringBuilder();
// Add some code with leading/trailing whitespcace
builder.append(" ABCD ");
System.out.println("Original Value of builder = *" + builder + "*");
System.out.println("Length of builder = " + builder.length());
System.out.println("Capacity of builder = " + builder.capacity());
// What do you think trimToSize does?
builder.trimToSize();
System.out.println("Current Value of builder = *" + builder + "*");
System.out.println("Length of builder = " + builder.length());
System.out.println("Capacity of builder = " + builder.capacity());
// builder.replace(0, builder.length(), builder.toString().strip()); //Introduced in Java 11
System.out.println("Next Value of builder = *" + builder + "*");
System.out.println("Length of builder = " + builder.length());
System.out.println("Capacity of builder = " + builder.capacity());
}
}
Output
Original Value of builder = * ABCD *
Length of builder = 23
Capacity of builder = 34
Current Value of builder = * ABCD *
Length of builder = 23
Capacity of builder = 23
Next Value of builder = *ABCD*
Length of builder = 4
Capacity of builder = 23
getChars
getChars
does not actually return anything from the method itself, but alters the data in one of the passed parameters.
String and StringBuilder both implement this method, but not through the CharSequence interface. So applying this method to a CharSequence, will give a compile error.
The destination parameter for the characters, the third parameter, must be an initialised char array.
For any other type, or the array is not initialised, it will give a compile error.
The destination character array size must be greater or equal to the length of the selected source plus the defined destination index. If you exceed the array size, you receive a runtime error
Finally, if you do not select any characters from the source by specifying sourceEndIndex equals sourceStartIndex, then your char array does not change at all.
StringBuffer
StringBuffer can be called as the thread-safe version of StringBuilder. Since it is thread-safe, all the public methods are synchronized and hence its methods performance is negatively impacted. It is also mutable, and used to be the only option before Java 5.
In comparision, we should use String vs StringBuilder when the strings are short and likely to be used throughout the application, without many concatenations. We should use StringBuilder if the string is build dynamically and concatenations occur in the application.