- 7.1 Introduction
- 7.2 Fundamentals of Characters and Strings
- 7.3 Class String
- 7.4 Class StringBuilder
- 7.5 Class Character
- 7.6 Tokenizing Strings
- 7.7 Intro to Natural Language Processing (NLP)-at the Root of Generative AI<sup><a id="fn7_5" href="ch07.xhtml#fn7_5a">5</a></sup>
- 7.8 Objects-Natural Case Study: Intro to Regular Expressions in NLP
- 7.9 Objects-Natural Security Case Study: pMa5tfEKwk59dTvC04Ft1IFQz9mEXnkfYXZwxk4ujGE=
- 7.10 Wrap-Up
7.4 Class StringBuilder
We now discuss the StringBuilder class’s features for creating and manipulating modifiable string information. Every StringBuilder can store a number of characters specified by its capacity. When that capacity is exceeded, a StringBuilder expands its capacity to accommodate more characters—the new capacity is twice the old capacity plus 2.
In programs that frequently perform String concatenation or other String modifications, implementing those operations with a StringBuilder is more efficient and avoids creating unnecessary extra String objects. Java can perform optimizations involving String objects—such as referring to one String object from multiple variables—because it knows these objects will not change. Use Strings for text that does not change.
7.4.1 Creating StringBuilder Objects
Class StringBuilder provides four constructors for initializing new StringBuilder objects. Figure 7.10 demonstrates three of these:
Line 6 uses the no-argument StringBuilder constructor to create an empty StringBuilder with a default capacity of 16 characters.
Line 7 uses the StringBuilder constructor with an integer argument to create an empty StringBuilder and the specified initial capacity (10 in this case). If you know the final size of the content you’ll build, you can use this constructor to preallocate that capacity, making your program more efficient because the StringBuilder will not have to expand to accommodate more text.
Line 8 uses the StringBuilder constructor that takes a String argument to create a StringBuilder containing the String’s characters. The StringBuilder’s initial capacity is the String’s length plus 16.
Lines 10–12 implicitly invoke StringBuilder method toString to output the contents of each StringBuilder.
1 // Fig. 7.10: StringBuilderConstructors.java
2 // StringBuilder constructors.
3
4 public class StringBuilderConstructors {
5 public static void main(String[] args) {
6 var buffer1 = new StringBuilder();
7 var buffer2 = new StringBuilder(10);
8 var buffer3 = new StringBuilder("hello");
9
10 System.out.printf("buffer1 = \"%s\"%n", buffer1);
11 System.out.printf("buffer2 = \"%s\"%n", buffer2);
12 System.out.printf("buffer3 = \"%s\"%n", buffer3);
13 }
14 }
buffer1 = "" buffer2 = "" buffer3 = "hello"
Fig. 7.10 | StringBuilder constructors.
7.4.2 Methods length, capacity, setLength and ensureCapacity
The StringBuilder class’s length and capacity methods return the number of characters currently in a StringBuilder and the number of characters that can be stored without allocating more memory, respectively. StringBuilder’s ensureCapacity method guarantees that a StringBuilder has at least the specified capacity, increasing the capacity if necessary. StringBuilder’s setLength method increases or decreases the length of a StringBuilder. Figure 7.11 demonstrates these methods.
1 // Fig. 7.11: StringBuilderCapLen.java
2 // StringBuilder length, setLength, capacity and ensureCapacity methods.
3
4 public class StringBuilderCapLen {
5 public static void main(String[] args) {
6 var buffer = new StringBuilder("Hello, how are you?");
7
8 System.out.printf("buffer = %s%nlength = %d%ncapacity = %d%n%n",
9 buffer.toString(), buffer.length(), buffer.capacity());
10
11 buffer.ensureCapacity(75);
12 System.out.printf("New capacity = %d%n%n", buffer.capacity());
13
14 buffer.setLength(10);
15 System.out.printf("New length = %d%nbuffer = %s%n",
16 buffer.length(), buffer.toString());
17 }
18 }
buffer = Hello, how are you? length = 19 capacity = 35 New capacity = 75 New length = 10 buffer = Hello, how
Fig. 7.11 | StringBuilder length, setLength, capacity and ensureCapacity methods.
The program contains one StringBuilder called buffer. Line 6 uses the StringBuilder constructor that takes a String argument to initialize the StringBuilder with "Hello, how are you?". Lines 8–9 print the StringBuilder’s contents, length and capacity. The buffer’s initial capacity is 35 because the constructor that takes a String argument initializes the capacity to the String’s length plus 16.
Line 11 calls ensureCapacity to expand the StringBuilder’s capacity to a minimum of 75 characters. The StringBuilder’s capacity remains unchanged if it’s more than method ensureCapacity’s argument.
Dynamically increasing a StringBuilder’s capacity frequently can degrade performance. If a StringBuilder’s size will increase repeatedly, setting its capacity high will improve performance by reducing the number of times the StringBuilder needs to reallocate its internal array.
Line 14 uses method setLength to set the length of the StringBuilder to 10. If the specified length is less than the StringBuilder’s length, its contents are truncated to the specified length—the subsequent characters are discarded. If the specified length is greater than the StringBuilder’s length, null characters ('\0') are appended until the StringBuilder’s total number of characters is equal to the specified length.
Generative AI
1 Prompt genAIs to explain why a StringBuilder adds 16 to its capacity when you initialize it with a String.
2 Section 7.4’s introduction mentioned that when a StringBuilder’s capacity is exceeded, it expands such that “the new capacity is twice the old capacity plus 2." Prompt genAIs to write Java code demonstrating this growth pattern.
7.4.3 Methods charAt, setCharAt, getChars and reverse
You can manipulate a StringBuilder’s characters with StringBuilder methods charAt, setCharAt, getChars and reverse (Fig. 7.12):
Method charAt (line 10) takes an integer argument and returns the character in the StringBuilder at that index.
Method getChars (line 13) copies characters from a StringBuilder into the character array passed as an argument. This method takes four arguments—the starting index from which characters should be copied, the index one past the last character to be copied, the character array into which to copy the characters and the starting index in the character array where the first copied character should be placed.
Method setCharAt (lines 20 and 21) takes an index and a character argument, and replaces the StringBuilder’s character at that index with the character argument.
Method reverse (line 24) reverses the contents of the StringBuilder.
For the StringBuilder methods that receive indices, attempting to access a character outside the bounds of the StringBuilder causes a IndexOutOfBoundsException.
1 // Fig. 7.12: StringBuilderChars.java
2 // StringBuilder methods charAt, setCharAt, getChars and reverse.
3
4 public class StringBuilderChars {
5 public static void main(String[] args) {
6 var buffer = new StringBuilder("hello there");
7
8 System.out.printf("buffer = %s%n", buffer.toString());
9 System.out.printf("Character at 0: %s%nCharacter at 4: %s%n%n",
10 buffer.charAt(0), buffer.charAt(4));
11
12 char[] charArray = new char[buffer.length()];
13 buffer.getChars(0, buffer.length(), charArray, 0);
14 System.out.print("The characters are: ");
15
16 for (char character : charArray) {
17 System.out.print(character);
18 }
19
20 buffer.setCharAt(0, 'H');
21 buffer.setCharAt(6, 'T');
22 System.out.printf("%n%nbuffer = %s", buffer.toString());
23
24 buffer.reverse();
25 System.out.printf("%n%nbuffer = %s%n", buffer.toString());
26 }
27 }
buffer = hello there Character at 0: h Character at 4: o The characters are: hello there buffer = Hello There buffer = erehT olleH
Fig. 7.12 | StringBuilder methods charAt, setCharAt, getChars and reverse.
Generative AI
1 Prompt genAIs with the code in Fig. 7.12, asking them to simplify the code and explain the changes they make.
7.4.4 append Methods
The StringBuilder class’s overloaded append methods (Fig. 7.13) add values of various types to the end of a StringBuilder. Versions are provided for each primitive type, character arrays, Strings, Objects, and more. Each method takes its argument, converts it to a String and appends it to the StringBuilder. In this example, the call
System.lineSeparator()
returns the system-specific line separator, which varies among operating systems.
1 // Fig. 7.13: StringBuilderAppend.java
2 // StringBuilder append methods.
3
4 public class StringBuilderAppend {
5 public static void main(String[] args) {
6 Object objectRef = "hello";
7 String string = "goodbye";
8 char[] charArray = {'a', 'b', 'c', 'd', 'e', 'f'};
9 boolean booleanValue = true;
10 char characterValue = 'Z';
11 int integerValue = 7;
12 long longValue = 10000000000L;
13 float floatValue = 2.5f;
14 double doubleValue = 33.333;
15
16 var lastBuffer = new StringBuilder("last buffer");
17 var buffer = new StringBuilder();
18
19 buffer.append(objectRef)
20 .append(System.lineSeparator())
21 .append(string)
22 .append(System.lineSeparator())
23 .append(charArray)
24 .append(System.lineSeparator())
25 .append(charArray, 0, 3)
26 .append(System.lineSeparator())
27 .append(booleanValue)
28 .append(System.lineSeparator())
29 .append(characterValue)
30 .append(System.lineSeparator())
31 .append(integerValue)
32 .append(System.lineSeparator())
33 .append(longValue)
34 .append(System.lineSeparator())
35 .append(floatValue)
36 .append(System.lineSeparator())
37 .append(doubleValue)
38 .append(System.lineSeparator())
39 .append(lastBuffer);
40
41 System.out.printf("buffer contains%n%s%n", buffer.toString());
42 }
43 }
buffer contains hello goodbye abcdef abc true Z 7 10000000000 2.5 33.333 last buffer
Fig. 7.13 | StringBuilder append methods.
Implementing + and += for Strings
The compiler can use StringBuilder and the append methods to implement the + and += String concatenation operators to avoid creating unnecessary extra String objects. For example, assuming the declarations
String string1 = "hello"; String string2 = "BC"; int value = 22;
the statement
String s = string1 + string2 + value;
concatenates "hello", "BC" and 22. The concatenation can be performed as follows:
String s = new StringBuilder().append("hello").append("BC").
append(22).toString();
First, the preceding statement creates an empty StringBuilder, then appends the Strings "hello" and "BC" and the integer 22. Next, StringBuilder’s toString method converts the StringBuilder to a String object to be assigned to String s. The statement
s += "!";
can be performed as follows:
s = new StringBuilder().append(s).append("!").toString();
This creates an empty StringBuilder, then appends the current contents of s followed by "!". Next, StringBuilder’s method toString (which must be called explicitly here) returns the StringBuilder’s contents as a String, and the result is assigned to s.
Generative AI
1 Prompt genAIs to rewrite the code in Fig. 7.13 to use String concatenation with the + operator, then compare the generated code to Fig. 7.13.
7.4.5 Insertion and Deletion Methods
The StringBuilder class’s overloaded insert methods insert values of various types at any valid position in a StringBuilder. Versions are provided for the primitive types, character arrays, Strings, Objects and more. Each method takes its second argument and inserts it at the index specified by the first argument. If the first argument is less than 0 or greater than the StringBuilder’s length, a StringIndexOutOfBoundsException occurs. The StringBuilder class’s delete and deleteCharAt methods delete characters at any position in a StringBuilder:
delete takes two arguments—the starting index and the index one past the end of the characters to delete. All characters beginning at the starting index up to but not including the ending index are deleted.
deleteCharAt takes one argument—the index of the character to delete.
Invalid indices cause both methods to throw a StringIndexOutOfBoundsException. Figure 7.14 demonstrates methods insert, delete and deleteCharAt.
1 // Fig. 7.14: StringBuilderInsertDelete.java
2 // StringBuilder methods insert, delete and deleteCharAt.
3
4 public class StringBuilderInsertDelete {
5 public static void main(String[] args) {
6 Object objectRef = "hello";
7 String string = "goodbye";
8 char[] charArray = {'a', 'b', 'c', 'd', 'e', 'f'};
9 boolean booleanValue = true;
10 char characterValue = 'K';
11 int integerValue = 7;
12 long longValue = 10000000;
13 float floatValue = 2.5f; // f suffix indicates that 2.5 is a float
14 double doubleValue = 33.333;
15
16 var buffer = new StringBuilder();
17
18 buffer.insert(0, objectRef);
19 buffer.insert(0, " "); // each of these contains two spaces
20 buffer.insert(0, string);
21 buffer.insert(0, " ");
22 buffer.insert(0, charArray);
23 buffer.insert(0, " ");
24 buffer.insert(0, charArray, 3, 3);
25 buffer.insert(0, " ");
26 buffer.insert(0, booleanValue);
27 buffer.insert(0, " ");
28 buffer.insert(0, characterValue);
29 buffer.insert(0, " ");
30 buffer.insert(0, integerValue);
31 buffer.insert(0, " ");
32 buffer.insert(0, longValue);
33 buffer.insert(0, " ");
34 buffer.insert(0, floatValue);
35 buffer.insert(0, " ");
36 buffer.insert(0, doubleValue);
37
38 System.out.printf(
39 "buffer after inserts:%n%s%n%n", buffer.toString());
40
41 buffer.deleteCharAt(10); // delete 5 in 2.5
42 buffer.delete(2, 6); // delete .333 in 33.333
43
44 System.out.printf(
45 "buffer after deletes:%n%s%n", buffer.toString());
46 }
47 }
buffer after inserts: 33.333 2.5 10000000 7 K true def abcdef goodbye hello buffer after deletes: 33 2. 10000000 7 K true def abcdef goodbye hello
Fig. 7.14 | StringBuilder methods insert, delete and deleteCharAt.
Generative AI
1 Prompt genAIs asking why some Java String and StringBuilder methods throw IndexOutOfBoundsExceptions but others throw StringIndexOutOfBoundsExceptions?
