TheDeveloperBlog.com


Java

Java StringBuilder Examples: append, insert

StringBuilder. String appends become increasingly expensive as strings become longer. More and more memory is required. Programs slow down.


A solution. The StringBuilder class in Java is a solution to this problem. It is mutable. It just reuses a single buffer. It speeds up appends, inserts.


An example. This imports java.lang.StringBuilder. We create a StringBuilder. We loop and append five strings to it. We convert the data into a String object.

Then: We display the resulting String to the Console with the System.out.println method.

Console
Based on:

Java 7

Java program that uses StringBuilder

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	// Create a new StringBuilder.
	StringBuilder builder = new StringBuilder();

	// Loop and append values.
	for (int i = 0; i < 5; i++) {
	    builder.append("abc ");
	}
	// Convert to string.
	String result = builder.toString();

	// Print result.
	System.out.println(result);
    }
}

Output

abc abc abc abc abc

In loops. Often we use StringBuilders in loops. Here we have an often-unknown number of iterations. And StringBuilder optimizes cases where many append() calls occur.

Therefore: Using StringBuilder in a loop may prevent a generate performance problem from developing.

For

Values. The StringBuilder can append many types of data. We are not restricted to strings. With the append() method, we can add ints, doubles, chars—any numeric type.

Numbers

Here: In this example, we call append() on the result of a previous append() call. Append returns the original StringBuilder.

Java program that appends values, StringBuilder

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	int value1 = 300;
	double value2 = 3.14;
	short value3 = 5;
	char value4 = 'A';

	// Create StringBuilder and add four values to it.
	StringBuilder builder = new StringBuilder();
	builder.append(value1).append("\n");
	builder.append(value2).append("\n");
	builder.append(value3).append("\n");
	builder.append(value4);

	// Display results.
	String result = builder.toString();
	System.out.println(result);
    }
}

Output

300
3.14
5
A

Insert. A StringBuilder has a mutable buffer. So we can quickly append, or insert, data. Here we use the insert method. It receives two arguments: an index, and a value we want to insert.

Index: This is the first argument. To insert after the second character, use the value 2. And to insert at the start, use zero.

String: We pass a string (or other value) as the second argument. This is the data that is placed into the StringBuilder.

Java program that uses insert

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	// Initialize StringBuilder with this value.
	StringBuilder builder = new StringBuilder("abc");

	// Insert this substring at position 2.
	builder.insert(2, "xyz");
	System.out.println(builder);
    }
}

Output

abxyzc

IndexOf. A StringBuilder can be searched. We use the indexOf method to search for a substring within the StringBuilder's data. This method searches forward.

Found: If the substring is found within the StringBuilder, the first index where it occurs is returned as an int.

Not found: If no matching substring is found, the special value negative one is returned. We must often check for -1 when using indexOf.

Java program that uses indexOf

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	StringBuilder builder = new StringBuilder("abc");

	// Try to find this substring.
	int result = builder.indexOf("bc");
	System.out.println(result);

	// This substring does not exist.
	int result2 = builder.indexOf("de");
	System.out.println(result2);
    }
}

Output

1
-1

Delete. This removes a range of characters. We pass it two int arguments. The first argument is the start index where removal is to begin. And the second argument is the end index.

Java program that uses delete

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	StringBuilder builder = new StringBuilder("carrot");

	// Delete characters from index 2 to index 5.
	builder.delete(2, 5);
	System.out.println(builder);
    }
}

Output

cat

Replace. This method accepts two indexes and replaces the characters in that range with a specified String. Replace on StringBuilder works differently than replace() on Strings.

Replace
Java program that uses replace method

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	// Create new StringBuilder.
	StringBuilder b = new StringBuilder("abc");

	// Replace second character with "xyz".
	b.replace(1, 2, "xyz");
	System.out.println(b);
    }
}

Output

axyzc

Combine two StringBuilders. We can append one StringBuilder to another. We simply call append() and pass the second StringBuilder as an argument. The two StringBuilders are combined.

Java that combines StringBuilders

public class Program {
    public static void main(String[] args) {

	StringBuilder builder = new StringBuilder("cat");
	StringBuilder builder2 = new StringBuilder("dog");

	// Combine two StringBuilders.
	builder.append(builder2);

	System.out.println(builder);
    }
}

Output

catdog

Substring. This method is found on the AbstractStringBuilder class. It provides the useful ability to extract a range of characters into a new string.

Arguments: The first argument is the start index of the desired substring. The second argument is last index (not the character count).

Java that uses substring

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	StringBuilder builder = new StringBuilder();
	builder.append("Forest");

	// Get substring after the first two characters.
	String omitFirstTwo = builder.substring(2);
	System.out.println(omitFirstTwo);

	// Get only the first two characters in a substring.
	String firstTwo = builder.substring(0, 2);
	System.out.println(firstTwo);
    }
}

Output

rest
Fo

Loop over chars. A for-loop can iterate over the characters in a StringBuilder. We access the length() method to get the StringBuilder's size and then use charAt() to access chars.

Length: This method returns the count of characters in the StringBuilder. The highest index is the count of chars minus one.

CharAt: This accesses a character within the StringBuilder. We can use it anywhere, not just in a for-loop.

Java that loops over StringBuilder chars

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	StringBuilder builder = new StringBuilder("magic");
	// Loop over the characters in this StringBuilder.
	for (int i = 0; i < builder.length(); i++) {
	    System.out.println(builder.charAt(i));
	}
    }
}

Output

m
a
g
i
c

SetLength. We can modify the length of a StringBuilder with setLength. This often is useful when we want to shorten or reduce the number of characters in the object.

Java that uses setLength method

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	StringBuilder builder = new StringBuilder("carrot");
	// Use setLength to remove characters from the end.
	builder.setLength(3);
	System.out.println(builder);
    }
}

Output

car

Capacity. Internally a StringBuilder resizes as its character count increases. This is slow. With a larger capacity, set in the constructor, we avoid these resizes.

Java that uses capacity

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	// Use a 100-char capacity.
	StringBuilder temp = new StringBuilder(100);
	// Add 100 characters to the StringBuilder.
	// ... Theoretically this is faster.
	for (int i = 0; i < 25; i++) {
	    temp.append("1234");
	}
	System.out.println(temp.length());
    }
}

Output

100

Reverse. This example reverses a StringBuilder. It calls the reverse() method. This is an easy to reverse a string—we first must place its contents in a StringBuilder.

Java that uses reverse

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	// A StringBuilder can be reversed.
	StringBuilder builder = new StringBuilder();
	builder.append("abc");
	builder.reverse();
	System.out.println(builder);
    }
}

Output

cba

Performance. A StringBuilder is massively faster in repeated appends than a String. This program demonstrates. It adds 10,000 numbers (and spaces) to a String, and to a StringBuilder.

Result: The String adds require significant time (251 ms) while the StringBuilder appends require less than 1 ms.

Java that times String, StringBuilder

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	long t1 = System.currentTimeMillis();

	// Version 1: add to string.
	String value = "";
	for (int i = 0; i < 10000; i++) {
	    value += Integer.toString(i) + ' ';
	}

	long t2 = System.currentTimeMillis();

	// Version 2: append to StringBuilder.
	StringBuilder builder = new StringBuilder();
	for (int i = 0; i < 10000; i++) {
	    builder.append(i).append(' ');
	}

	long t3 = System.currentTimeMillis();

	// ... Lengths are equal.
	System.out.println(value.length());
	System.out.println(builder.length());

	// ... Times.
	System.out.println(t2 - t1);
	System.out.println(t3 - t2);
    }
}

Results

48890
48890
251 ms, String + operator    (20000 adds)
  0 ms, StringBuilder append (20000 calls)

Capacity performance. Here we revisit capacity. In this test, the first StringBuilder grows to a size of one million chars with no capacity set.

And: The second StringBuilder meanwhile uses an exact capacity of 1,000,000. The two are benchmarked.

Result: The exact capacity makes the second StringBuilder nearly twice as fast to complete its meaningless task.

Java that benchmarks capacity use

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	long t1 = System.currentTimeMillis();

	// Version 1: does not use capacity.
	StringBuilder builder = new StringBuilder();
	for (int i = 0; i < 1000000; i++) {
	    builder.append(' ');
	}

	long t2 = System.currentTimeMillis();

	// Version 2: uses exact capacity.
	StringBuilder builder2 = new StringBuilder(1000000);
	for (int i = 0; i < 1000000; i++) {
	    builder2.append(' ');
	}

	long t3 = System.currentTimeMillis();

	// ... Times.
	System.out.println(t2 - t1);
	System.out.println(t3 - t2);
    }
}

Results

10 ms, no capacity
 6 ms, exact capacity

Append String versus char. Here is another benchmark. It compares calling append() with a one-character String literal versus a char. The String argument is slower.

When possible: It is faster to use a char argument to append() than a String argument. I have found this helps many programs.

Java that times String, char appends

import java.lang.StringBuilder;

public class Program {
    public static void main(String[] args) {

	long t1 = System.currentTimeMillis();

	// Version 1: appends one-char strings.
	StringBuilder builder = new StringBuilder();
	for (int i = 0; i < 1000000; i++) {
	    builder.append("X");
	}

	long t2 = System.currentTimeMillis();

	// Version 2: appends chars directly.
	StringBuilder builder2 = new StringBuilder();
	for (int i = 0; i < 1000000; i++) {
	    builder2.append('X');
	}

	long t3 = System.currentTimeMillis();

	// ... Times.
	System.out.println(t2 - t1);
	System.out.println(t3 - t2);
    }
}

Results

15 ms, append() String argument
 7 ms, append() char argument

Char arrays. We can use a char array instead of a StringBuilder to create strings. In my benchmarks this is faster, but arrays cannot be resized so is less flexible.

Char Arrays

StringBuffer. This is an older version of StringBuilder. The two classes are almost the same, except StringBuffer is thread-safe and somewhat slower.

StringBuffer

An improvement. StringBuilder helps in many program parts. But often its best uses are in loops. In these cases, many iterations occur, and many append calls are invoked.


Speed. This improves performance, a key goal. For simple situations, a String may be faster. And if another method requires a String argument, this is also likely.