Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

StringBuilder Capacity Management

Problem Statement

Write a Java program that demonstrates StringBuilder’s capacity resizing by appending strings and monitoring capacity changes using the capacity() method. The program should analyze when resizing occurs and how the capacity adjusts based on the appended content. Test the implementation with different scenarios, including appending small strings, large strings, and using StringBuilder instances with varying initial capacities. You can visualize this as filling a stretchable notebook, where the notebook expands its pages (capacity) automatically when you add more notes, and you track how and when it grows to accommodate the text.

Input: A series of strings to append to StringBuilder instances with different initial configurations (e.g., default capacity, specified initial capacity). Output: The final string, a log of capacity changes after each append operation, and an analysis of when resizing occurs. Constraints:

  • String lengths are between 0 and 10^5.
  • Strings contain printable ASCII characters.
  • Initial capacities are non-negative integers.
  • The input strings may be null or empty. Example:
  • Input: Append "hello", " world" to a StringBuilder with default capacity (16).
  • Output:
    Initial capacity: 16
    After appending "hello": length=5, capacity=16
    After appending " world": length=11, capacity=16
    Final string: "hello world"
    
  • Explanation: No resizing occurs as the total length (11) fits within the initial capacity (16).
  • Input: Append a 20-character string to a StringBuilder with default capacity (16).
  • Output:
    Initial capacity: 16
    After appending: length=20, capacity=34
    Final string: "abcdefghijklmnopqrst"
    
  • Explanation: Resizing occurs because 20 exceeds 16, new capacity = (16 * 2) + 2 = 34.

Pseudocode

FUNCTION demonstrateCapacityManagement(testCases)
    FOR each testCase in testCases
        SET initialCapacity to testCase.initialCapacity
        SET strings to testCase.strings
        CREATE stringBuilder with initialCapacity
        PRINT initial capacity
        FOR each string in strings
            SET oldCapacity to stringBuilder.capacity()
            APPEND string to stringBuilder
            SET newCapacity to stringBuilder.capacity()
            PRINT length, capacity, and whether resizing occurred
        ENDFOR
        PRINT final string
    ENDFOR
ENDFUNCTION

FUNCTION main()
    SET testCases to array of (initialCapacity, strings) pairs
    CALL demonstrateCapacityManagement(testCases)
ENDFUNCTION

Algorithm Steps

  1. Define a method to demonstrate capacity management: a. For each test case, create a StringBuilder with the specified initial capacity. b. Print the initial capacity using capacity(). c. For each string to append:
    • Record the current capacity.
    • Append the string using StringBuilder.append.
    • Check the new capacity and note if resizing occurred (capacity increased).
    • Print the current length, capacity, and resizing status. d. Print the final string.
  2. Handle null or empty strings by skipping or appending empty content.
  3. In the main method, test with different scenarios:
    • Default capacity (16) with small strings.
    • Default capacity with a large string that triggers resizing.
    • Custom initial capacity with multiple appends.
    • Empty or null strings.
  4. Analyze resizing: StringBuilder doubles the current capacity and adds 2 when the length exceeds the capacity.

Java Implementation

public class StringBuilderCapacityManagement {
    // Demonstrates StringBuilder capacity resizing
    public void demonstrateCapacityManagement(String[][] testCases, int[] initialCapacities) {
        for (int i = 0; i < testCases.length; i++) {
            String[] strings = testCases[i];
            int initialCapacity = initialCapacities[i];
            System.out.println("Test case " + (i + 1) + ":");
            System.out.println("Initial capacity: " + initialCapacity);
            
            StringBuilder sb = new StringBuilder(initialCapacity);
            for (int j = 0; j < strings.length; j++) {
                String str = strings[j] != null ? strings[j] : "";
                int oldCapacity = sb.capacity();
                sb.append(str);
                int newCapacity = sb.capacity();
                System.out.println("After appending \"" + (str.length() > 20 ? str.substring(0, 20) + "..." : str) + "\": " +
                                   "length=" + sb.length() + ", capacity=" + newCapacity +
                                   (newCapacity > oldCapacity ? " (resized)" : ""));
            }
            System.out.println("Final string: \"" + (sb.length() > 50 ? sb.substring(0, 50) + "..." : sb.toString()) + "\"\n");
        }
    }

    // Main method to test capacity management
    public static void main(String[] args) {
        StringBuilderCapacityManagement manager = new StringBuilderCapacityManagement();

        // Test cases
        String[][] testCases = {
            {"hello", " world"},                    // Small strings, default capacity
            {generateLargeString(20)},             // Large string, triggers resizing
            {"a", "b", "c", "d"},                 // Multiple small strings, custom capacity
            {""},                                  // Empty string
            {null}                                 // Null string
        };
        int[] initialCapacities = {16, 16, 5, 16, 16}; // Corresponding initial capacities

        manager.demonstrateCapacityManagement(testCases, initialCapacities);
    }

    // Helper method to generate a large string
    private static String generateLargeString(int length) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append((char) ('a' + (i % 26)));
        }
        return sb.toString();
    }
}

Output

Running the main method produces (actual capacities may vary slightly depending on JVM implementation):

Test case 1:
Initial capacity: 16
After appending "hello": length=5, capacity=16
After appending " world": length=11, capacity=16
Final string: "hello world"

Test case 2:
Initial capacity: 16
After appending "abcdefghijklmnopqrst...": length=20, capacity=34 (resized)
Final string: "abcdefghijklmnopqrst"

Test case 3:
Initial capacity: 5
After appending "a": length=1, capacity=5
After appending "b": length=2, capacity=5
After appending "c": length=3, capacity=5
After appending "d": length=4, capacity=5
Final string: "abcd"

Test case 4:
Initial capacity: 16
After appending "": length=0, capacity=16
Final string: ""

Test case 5:
Initial capacity: 16
After appending "": length=0, capacity=16
Final string: ""

Explanation:

  • Test case 1: Appends "hello", " world". Length (11) < capacity (16), no resizing.
  • Test case 2: Appends 20-character string. Length (20) > 16, resizes to (16 * 2) + 2 = 34.
  • Test case 3: Custom capacity 5, appends four single characters. Length (4) ≤ 5, no resizing.
  • Test case 4: Empty string, no change in length or capacity.
  • Test case 5: Null string treated as empty, no change.

How It Works

  • StringBuilder Capacity: Represents the size of the internal character array. Default is 16 if not specified.
  • Resizing: When the length exceeds capacity, StringBuilder allocates a new array with capacity = (oldCapacity * 2) + 2.
  • demonstrateCapacityManagement:
    • Creates StringBuilder with specified initial capacity.
    • Tracks capacity before and after each append.
    • Reports resizing when new capacity exceeds old capacity.
  • Example Trace (Test case 2):
    • Initial: capacity = 16, length = 0.
    • Append "abcdefghijklmnopqrst" (20 chars): length = 20 > 16, new capacity = (16 * 2) + 2 = 34.
  • Main Method: Tests with small strings, large strings triggering resizing, custom capacity, and edge cases.
  • Analysis: Resizing occurs when the total length after appending exceeds the current capacity, doubling the capacity plus 2 to accommodate future appends efficiently.

Complexity Analysis Table

OperationTime ComplexitySpace Complexity
AppendO(m)O(m)
Capacity CheckO(1)O(1)
ResizingO(n)O(n)
Full AlgorithmO(k * m)O(n + k * m)

Note:

  • n is the current length of the StringBuilder, m is the length of the appended string, k is the number of append operations.
  • Append: O(m) for copying characters, amortized O(1) if no resizing.
  • Resizing: O(n) when copying the internal array to a larger one.
  • Full algorithm: O(k * m) time for k appends, O(n + k * m) space for the final StringBuilder content.
  • Worst case: Frequent resizing for large strings increases time and space.

✅ Tip: Set an appropriate initial capacity for StringBuilder when the expected size is known to minimize resizing. Use capacity() to monitor and understand resizing behavior during development.

⚠ Warning: Avoid unnecessarily small initial capacities, as frequent resizing can degrade performance. Handle null inputs to prevent unexpected behavior during append operations.