Using StringBuilder and StringBuffer in Java
Course: Core Java Training
Topic: Using StringBuilder and StringBuffer
Course Link: Core Java Training Course
Demo Link: Register for a Free Course Demo
Academy Website: JustAcademy
1. Introduction to StringBuilder and StringBuffer
In Java, strings are represented by the String class. A String object is immutable, which means its contents cannot be changed after the object is created. Whenever a program modifies a String, Java creates a new String object for the resulting value.
Repeatedly creating new String objects can cause unnecessary object creation when a program performs many concatenation or modification operations. Java provides the StringBuilder and StringBuffer classes to work with mutable sequences of characters.
Both classes allow developers to append, insert, delete, replace, and reverse characters without creating a new object for every modification.
Learning Objectives
- Understand mutable character sequences in Java.
- Learn the purpose of StringBuilder and StringBuffer.
- Compare String, StringBuilder, and StringBuffer.
- Use common methods such as append(), insert(), delete(), replace(), and reverse().
- Understand thread safety and synchronization.
- Choose the appropriate class for different programming situations.
2. What Is StringBuilder?
StringBuilder is a Java class used to create and modify a mutable sequence of characters. It is useful when a program needs to construct or change text repeatedly.
StringBuilder is not synchronized. Its methods do not provide built-in synchronization for safe concurrent modification by multiple threads. This generally makes it a suitable choice for local text manipulation performed by a single thread.
Syntax
StringBuilder builder = new StringBuilder();
StringBuilder builderWithText = new StringBuilder("Hello");
Example
public class StringBuilderExample {
public static void main(String[] args) {
StringBuilder builder = new StringBuilder("Hello");
builder.append(" Java");
System.out.println(builder);
}
}
Output:
Hello Java
The append() method adds text to the existing character sequence. The builder itself is modified, and the returned reference points to the same StringBuilder object.
3. What Is StringBuffer?
StringBuffer is another Java class for creating and modifying a mutable sequence of characters. Its methods are synchronized, which helps coordinate access to individual operations when the same StringBuffer instance is shared by multiple threads.
StringBuffer can be useful when multiple threads need to work with the same mutable text object. However, synchronization of individual methods does not automatically make a sequence of several operations atomic. Additional synchronization or another coordination mechanism may be necessary when a complete multi-step operation must be performed as one unit.
Syntax
StringBuffer buffer = new StringBuffer();
StringBuffer bufferWithText = new StringBuffer("Hello");
Example
public class StringBufferExample {
public static void main(String[] args) {
StringBuffer buffer = new StringBuffer("Hello");
buffer.append(" Java");
System.out.println(buffer);
}
}
Output:
Hello Java
Like StringBuilder, StringBuffer supports common text modification operations. The main distinction is that StringBuffer synchronizes its methods, while StringBuilder does not.
4. Understanding Mutable and Immutable Strings
Immutable String
String text = "Java";
text.concat(" Programming");
System.out.println(text);
Output:
Java
The concat() method returns a new String. Since the returned value is not assigned back to text, the original variable still refers to "Java".
Mutable StringBuilder
StringBuilder text = new StringBuilder("Java");
text.append(" Programming");
System.out.println(text);
Output:
Java Programming
The StringBuilder object's contents are changed by the append operation.
Mutable StringBuffer
StringBuffer text = new StringBuffer("Java");
text.append(" Programming");
System.out.println(text);
Output:
Java Programming
StringBuffer also changes its existing character sequence through the append operation.
5. Difference Between String, StringBuilder, and StringBuffer
| Feature |
String |
StringBuilder |
StringBuffer |
| Mutability |
Immutable |
Mutable |
Mutable |
| Modification |
Produces a new String when content changes |
Modifies its character sequence |
Modifies its character sequence |
| Synchronization |
Immutable content; no synchronization needed for its contents |
Methods are not synchronized |
Methods are synchronized |
| Typical use |
Fixed text and string values |
Repeated text changes in a single-threaded context |
Shared mutable text when synchronized methods are useful |
| Performance considerations |
Repeated concatenation can create extra objects |
Often preferred for repeated modifications without synchronization |
Synchronization may add overhead |
| Common methods |
concat(), substring(), equals() |
append(), insert(), delete(), reverse() |
append(), insert(), delete(), reverse() |
StringBuilder is not guaranteed to outperform StringBuffer in every situation. Actual performance depends on the workload, Java version, and how the code is used. Prefer the class that fits the program's correctness and concurrency requirements.
6. Creating StringBuilder and StringBuffer Objects
Using the Default Constructor
StringBuilder sb = new StringBuilder();
StringBuffer sf = new StringBuffer();
Both objects begin with an empty character sequence and can grow as text is appended. Their default initial capacity is 16 characters.
Using a String Argument
StringBuilder sb = new StringBuilder("Core Java");
StringBuffer sf = new StringBuffer("Core Java");
The supplied text becomes the initial content of the object. The initial capacity is the length of that text plus 16.
Using a Capacity Argument
StringBuilder sb = new StringBuilder(50);
StringBuffer sf = new StringBuffer(50);
The capacity indicates how much character storage is initially available before the internal storage needs to grow. Capacity is not the same as the current length.
7. The append() Method
The append() method adds a value to the end of the existing character sequence. It supports strings, characters, numbers, booleans, character arrays, and other supported types.
Example
public class AppendExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Java");
sb.append(" Programming");
sb.append(" ");
sb.append(2026);
System.out.println(sb);
}
}
Output:
Java Programming 2026
Appending Different Data Types
StringBuilder sb = new StringBuilder();
sb.append("Age: ");
sb.append(25);
sb.append(", Active: ");
sb.append(true);
System.out.println(sb);
Output:
Age: 25, Active: true
Practical use: append() is commonly used to construct messages, logs, SQL text, reports, and formatted output. When building SQL queries, use prepared statements and parameters for user-supplied values rather than concatenating untrusted input.
8. The insert() Method
The insert() method inserts a value at a specified position in the existing sequence. Characters at and after that position shift to the right.
Syntax
builder.insert(index, value);
Example
public class InsertExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Hello Java");
sb.insert(6, "Core ");
System.out.println(sb);
}
}
Output:
Hello Core Java
The index must be between zero and the current length, inclusive. An invalid index causes an IndexOutOfBoundsException.
9. The replace() Method
The replace() method replaces characters between a starting index and an ending index. The start index is inclusive, while the end index is exclusive.
Example
public class ReplaceExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("I like Python");
sb.replace(7, 13, "Java");
System.out.println(sb);
}
}
Output:
I like Java
Here, the characters at positions 7 through 12 are replaced with "Java". This method replaces a range by index; it is not the same as globally searching for a matching word.
10. The delete() and deleteCharAt() Methods
The delete() method removes a range of characters. The deleteCharAt() method removes one character at a specified index.
Using delete()
StringBuilder sb = new StringBuilder("Hello World");
sb.delete(5, 11);
System.out.println(sb);
Output:
Hello
Using deleteCharAt()
StringBuilder sb = new StringBuilder("Java!");
sb.deleteCharAt(4);
System.out.println(sb);
Output:
Java
Check the indexes before removing characters. An invalid index or range can cause an IndexOutOfBoundsException.
11. The reverse() Method
The reverse() method reverses the order of characters in the current sequence. It is available in both StringBuilder and StringBuffer.
Example
public class ReverseExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Java");
sb.reverse();
System.out.println(sb);
}
}
Output:
avaJ
Checking a Palindrome
public class PalindromeExample {
public static void main(String[] args) {
String word = "madam";
String reversed = new StringBuilder(word).reverse().toString();
if (word.equals(reversed)) {
System.out.println("Palindrome");
} else {
System.out.println("Not a palindrome");
}
}
}
Output:
Palindrome
This example compares the original String with a reversed String. For case-insensitive or punctuation-insensitive palindrome checking, normalize the input before comparing.
12. Other Useful StringBuilder and StringBuffer Methods
| Method |
Purpose |
Example |
| length() |
Returns the number of characters currently in the sequence. |
sb.length() |
| capacity() |
Returns the current storage capacity. |
sb.capacity() |
| charAt(index) |
Returns the character at a specified index. |
sb.charAt(0) |
| setCharAt(index, ch) |
Changes the character at a specified index. |
sb.setCharAt(0, 'J') |
| substring(start) |
Returns a String containing characters from the specified start index to the end. |
sb.substring(5) |
| substring(start, end) |
Returns a String for the specified range, with the end index excluded. |
sb.substring(0, 4) |
| indexOf(text) |
Finds the first occurrence of a string. |
sb.indexOf("Java") |
| setLength(length) |
Changes the sequence length, truncating or adding null characters as needed. |
sb.setLength(4) |
| ensureCapacity(minimum) |
Requests sufficient capacity for a specified minimum. |
sb.ensureCapacity(100) |
| toString() |
Creates a String representation of the current sequence. |
sb.toString() |
| trimToSize() |
Attempts to reduce capacity to match the current length. |
sb.trimToSize() |
13. Understanding length() and capacity()
The length() method returns how many characters are currently stored. The capacity() method returns how many characters can fit in the current internal storage before it needs to grow.
Example
public class CapacityExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Java");
System.out.println("Length: " + sb.length());
System.out.println("Capacity: " + sb.capacity());
}
}
Output:
Length: 4
Capacity: 20
The initial capacity is 16 plus the length of the supplied string, so the capacity is 20 in this example. If more characters are appended than the available capacity can hold, the internal storage grows automatically.
14. Converting StringBuilder or StringBuffer to String
Methods that expect a String may require conversion from a StringBuilder or StringBuffer. Use toString() to obtain a String containing the current characters.
Example
public class ConversionExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Core Java");
String text = sb.toString();
System.out.println(text);
System.out.println(text.getClass().getSimpleName());
}
}
Output:
Core Java
String
The returned String is immutable. Changing the StringBuilder afterward does not change the String value that was already created.
15. StringBuilder and StringBuffer in Multithreaded Programs
Thread safety matters when multiple threads access the same mutable object. StringBuilder does not synchronize its methods, so concurrent modifications to one shared instance can interfere with one another. StringBuffer synchronizes its individual methods, providing more protection for shared access.
Choosing the Appropriate Class
- Use StringBuilder for local operations in a single thread or when external synchronization safely manages access.
- Consider StringBuffer when multiple threads share one mutable character sequence and synchronized methods suit the design.
- Remember that separate StringBuilder instances can safely be used independently by different threads.
- Do not assume that calling several synchronized StringBuffer methods makes the entire sequence of calls atomic.
Example of a Shared StringBuffer
public class SharedBufferExample {
public static void main(String[] args) throws InterruptedException {
StringBuffer buffer = new StringBuffer();
Thread first = new Thread(() -> {
for (int i = 0; i < 100; i++) {
buffer.append("A");
}
});
Thread second = new Thread(() -> {
for (int i = 0; i < 100; i++) {
buffer.append("B");
}
});
first.start();
second.start();
first.join();
second.join();
System.out.println(buffer.length());
}
}
Possible output:
200
In this example, each append call is synchronized by StringBuffer. The order of A and B characters can vary. The example assumes the threads only append and that no other code modifies the buffer concurrently.
16. Performance Considerations
StringBuilder is often a good choice for repeatedly constructing text in a single thread because its methods do not incur StringBuffer's built-in synchronization. StringBuffer may be useful when synchronized methods are appropriate for shared mutable state.
Repeated concatenation of immutable Strings in a loop can create many intermediate objects. A builder often reduces that object creation by modifying one character sequence repeatedly. However, Java compilers and runtimes can optimize some concatenation expressions, so the actual difference depends on the code and runtime.
Example: Repeated Concatenation
String result = "";
for (int i = 0; i < 5; i++) {
result += i;
}
System.out.println(result);
Output:
01234
Using StringBuilder
StringBuilder result = new StringBuilder();
for (int i = 0; i < 5; i++) {
result.append(i);
}
System.out.println(result);
Output:
01234
For large or repeated text-building operations, StringBuilder is commonly preferred. For very small expressions, ordinary concatenation can be perfectly readable and efficient. Benchmark realistic workloads before making performance claims.
17. Practical Example: Building a Student Report
The following program demonstrates how StringBuilder can combine multiple values into a readable report.
public class StudentReport {
public static void main(String[] args) {
StringBuilder report = new StringBuilder();
report.append("Student Report\n");
report.append("------------------\n");
report.append("Name: Riya\n");
report.append("Course: Core Java\n");
report.append("Score: ");
report.append(92);
report.append("%\n");
report.append("Status: Passed");
System.out.println(report.toString());
}
}
Output:
Student Report
------------------
Name: Riya
Course: Core Java
Score: 92%
Status: Passed
This approach is useful for generating reports, receipts, summaries, logs, and other text that is built from multiple values.
18. Common Mistakes and Troubleshooting
| Mistake |
Explanation |
Solution |
Using == to compare content |
== compares object references, not character content. |
Use toString().equals(otherString) when comparing with a String. |
| Confusing length and capacity |
Length counts current characters; capacity describes available internal storage. |
Use length() for content size and capacity() for storage capacity. |
| Using invalid indexes |
Some methods throw IndexOutOfBoundsException for invalid positions. |
Check the current length and method's index rules. |
| Assuming StringBuilder is thread-safe |
Its methods are not synchronized. |
Use appropriate synchronization or choose a suitable concurrency design. |
| Assuming StringBuffer makes every workflow atomic |
Individual synchronized method calls do not automatically protect a multi-step operation as one unit. |
Synchronize the whole operation when required. |
| Forgetting to call toString() |
A method may require a String rather than a mutable builder. |
Use builder.toString() where a String is required. |
| Overusing mutable builders |
Simple concatenation may be clearer for a short expression. |
Choose the simplest approach that fits the workload. |
19. Best Practices
- Prefer StringBuilder for repeated text modifications in ordinary single-threaded code.
- Use StringBuffer only when its synchronized operations fit the application's shared-state requirements.
- Choose a reasonable initial capacity when the expected output size is known and large enough to matter.
- Use meaningful variable names such as
messageBuilder or reportBuffer.
- Use
toString() when a String result is required.
- Check indexes and ranges carefully when using insert(), delete(), and replace().
- Do not rely on synchronization alone to solve every concurrency problem; protect compound operations where necessary.
- Use prepared statements for database parameters instead of assembling SQL from untrusted input.
- Prefer clear, maintainable code over premature micro-optimization.
20. Practice Exercises
- Create a StringBuilder object containing your name and append your course name.
- Write a program that inserts the word "Core" into the text "Java Training".
- Replace "Python" with "Java" in a StringBuilder object.
- Remove all characters after a given index using delete().
- Reverse a word and check whether it is a palindrome.
- Build a shopping receipt containing product names, quantities, and prices.
- Print the length and capacity of a StringBuilder before and after appending text.
- Write a short program that demonstrates converting a StringBuilder into a String.
- Compare the intended uses of String, StringBuilder, and StringBuffer in a short explanation.
- Create a multithreaded example that shares a StringBuffer and prints its final length.
21. Interview Questions and Answers
Q1. What is StringBuilder in Java?
StringBuilder is a mutable sequence of characters that supports repeated text modifications without requiring a new object for every operation.
Q2. What is StringBuffer?
StringBuffer is a mutable sequence of characters whose methods are synchronized.
Q3. What is the main difference between StringBuilder and StringBuffer?
StringBuilder methods are not synchronized, while StringBuffer methods are synchronized. This affects their suitability for shared mutable state and may affect performance.
Q4. Why is StringBuilder commonly used in loops?
It allows the program to append text to a mutable character sequence rather than repeatedly producing new intermediate String values.
Q5. Are StringBuilder and StringBuffer immutable?
No. Both are mutable, so operations can change their character sequences.
Q6. What does append() do?
It adds a value to the end of the existing character sequence.
Q7. What is the difference between length() and capacity()?
length() returns the number of current characters. capacity() returns the available internal storage capacity before the sequence needs to grow.
Q8. What does reverse() do?
It reverses the order of characters in the sequence.
Q9. How can a StringBuilder be converted to a String?
Call its toString() method.
Q10. Is StringBuffer always the best choice for multithreaded applications?
No. It synchronizes individual methods, but the overall design still needs correct coordination for compound operations. Other approaches may be more suitable depending on the application.
Q11. Can StringBuilder be used safely by multiple threads?
Independent StringBuilder instances can be used by separate threads. Concurrently modifying the same instance without coordination is unsafe.
Q12. What happens if an invalid index is passed to insert() or deleteCharAt()?
These methods can throw an IndexOutOfBoundsException.
22. Quick Revision
- String: immutable sequence of characters.
- StringBuilder: mutable and not synchronized; commonly used for repeated text changes in single-threaded code.
- StringBuffer: mutable and synchronizes its methods.
- append(): adds content at the end.
- insert(): adds content at a specified position.
- replace(): replaces a range of characters.
- delete(): removes a range of characters.
- deleteCharAt(): removes one character.
- reverse(): reverses the sequence.
- length(): returns the number of current characters.
- capacity(): returns the current storage capacity.
- toString(): returns a String representation of the current contents.
23. Conclusion
StringBuilder and StringBuffer are essential Java classes for working with mutable text. Both provide methods for appending, inserting, replacing, deleting, and reversing characters. StringBuilder is generally a convenient choice for repeated text construction when a shared synchronized object is not needed, while StringBuffer offers synchronized methods for certain shared-state scenarios.
Understanding their mutability, method behavior, capacity, and thread-safety differences helps developers write clearer and more efficient Java programs. Practice the examples and exercises to become comfortable using both classes in real-world applications.
24. Further Learning Resources