String Handling in Java: Immutability of Strings, `StringBuilder` vs. `StringBuffer`

Abhishek Kumar - Oct 2 - - Dev Community

In Java, strings are handled differently from other objects due to their immutability. Java also provides StringBuilder and StringBuffer classes to work with mutable sequences of characters, offering more flexibility for string manipulation.


1. Immutability of Strings

In Java, the String class is immutable, meaning once a String object is created, it cannot be changed. Any modification to a string (like concatenation or replacement) results in the creation of a new String object.

Key Features of String Immutability:

  • Thread Safety: Since strings are immutable, they can be safely shared across multiple threads without risk of being modified by one thread while being used by another.
  • Performance: String immutability helps in memory optimization by enabling string interning, where the JVM can store and reuse the same string in a string pool.
  • Security: Immutable strings are safe for use in security-sensitive code, such as database connections or file paths, as they cannot be changed once created.

Example of Immutability:

public class StringImmutability {
    public static void main(String[] args) {
        String str = "Hello";
        str = str.concat(", World!");  // This creates a new String object
        System.out.println(str);  // Output: Hello, World!
    }
}
Enter fullscreen mode Exit fullscreen mode
  • In this example, the original "Hello" string remains unchanged, and the concat method creates a new string "Hello, World!".

2. Mutable Strings: StringBuilder and StringBuffer

To efficiently modify strings, Java provides StringBuilder and StringBuffer. These classes allow mutable sequences of characters, making them more suitable for situations where frequent modifications to strings are required.

Key Differences Between StringBuilder and StringBuffer:

Feature StringBuilder StringBuffer
Mutability Mutable Mutable
Thread Safety Not thread-safe Thread-safe (synchronized)
Performance Faster due to lack of synchronization Slower due to synchronization
Use Case Preferred in single-threaded contexts Preferred in multi-threaded contexts

3. StringBuilder

StringBuilder is a mutable class that allows modification of strings without creating new objects. It is faster than StringBuffer because it is not synchronized, meaning it does not provide thread safety.

Example of Using StringBuilder:

public class StringBuilderExample {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Hello");
        sb.append(", World!");  // Modifying the existing object
        System.out.println(sb.toString());  // Output: Hello, World!
    }
}
Enter fullscreen mode Exit fullscreen mode
  • In this example, the StringBuilder object is modified directly with append(), without creating a new object.
  • This makes StringBuilder much more efficient than String for tasks that involve frequent string modifications.

Common Methods of StringBuilder:

  • append(String s): Adds the string to the end of the current sequence.
  • insert(int offset, String s): Inserts the string at the specified position.
  • delete(int start, int end): Removes characters in the given range.
  • reverse(): Reverses the sequence.

4. StringBuffer

StringBuffer is similar to StringBuilder, but it is synchronized, making it thread-safe. This means that multiple threads can access it safely, but synchronization comes with a performance cost.

Example of Using StringBuffer:

public class StringBufferExample {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("Hello");
        sb.append(", World!");  // Modifying the existing object
        System.out.println(sb.toString());  // Output: Hello, World!
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Similar to StringBuilder, StringBuffer allows direct modification of the string. However, it is slower due to the overhead of synchronization.

Common Methods of StringBuffer:

  • Same as StringBuilder, with methods like append(), insert(), delete(), and reverse(), but thread-safe.

5. Performance Comparison: String vs. StringBuilder vs. StringBuffer

String (Immutable):

  • Slower for repeated modifications because every change creates a new object.
  • Best for read-only or fixed string operations.

StringBuilder (Mutable, Not Synchronized):

  • Faster for string concatenation and modification.
  • Best for single-threaded applications or when thread safety is not a concern.

StringBuffer (Mutable, Synchronized):

  • Slower than StringBuilder due to thread-safety (synchronization).
  • Best for multi-threaded applications where strings are modified by multiple threads.

6. Practical Use Case Scenarios

  • Use String: For simple string operations or when strings are not frequently modified.

    • Example: Assigning a fixed message, logging a constant string.
  • Use StringBuilder: For frequent modifications in a single-threaded context.

    • Example: Concatenating strings in a loop.
  StringBuilder sb = new StringBuilder();
  for (int i = 0; i < 5; i++) {
      sb.append("Iteration ").append(i).append(" ");
  }
  System.out.println(sb.toString());
Enter fullscreen mode Exit fullscreen mode
  • Use StringBuffer: In multi-threaded environments where multiple threads may modify the same string.
    • Example: Modifying shared strings in a multi-threaded logging system.
  StringBuffer sb = new StringBuffer();
  sb.append("Thread-safe modifications");
Enter fullscreen mode Exit fullscreen mode

7. Conclusion

  • Strings in Java are immutable for performance, security, and thread safety reasons.
  • StringBuilder is the best choice for frequent modifications in single-threaded applications due to its speed.
  • StringBuffer is the thread-safe alternative to StringBuilder and is used in multi-threaded environments where synchronization is required.

Choosing the right string handling class depends on whether you need immutability, performance, or thread safety.

Here are some small programs to help refresh your understanding of String immutability, StringBuilder, and StringBuffer in Java:


1. Immutability of Strings

This program demonstrates how strings are immutable and how every modification results in a new object.

public class StringImmutabilityDemo {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = str1.concat(" World");

        System.out.println("Original String: " + str1);  // Output: Hello
        System.out.println("Modified String: " + str2);  // Output: Hello World
    }
}
Enter fullscreen mode Exit fullscreen mode
  • In this example, str1 is not modified after concatenation; a new string str2 is created.

2. Using StringBuilder for Efficient Concatenation

This program shows how to use StringBuilder to efficiently concatenate strings.

public class StringBuilderDemo {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Hello");

        sb.append(" World");
        sb.append("!");

        System.out.println("Resulting String: " + sb.toString());  // Output: Hello World!
    }
}
Enter fullscreen mode Exit fullscreen mode
  • The same StringBuilder object is modified multiple times without creating new objects, making it more efficient for frequent modifications.

3. Using StringBuffer for Thread-Safe Concatenation

This program demonstrates the use of StringBuffer in a thread-safe manner.

public class StringBufferDemo {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("Hello");

        sb.append(" World");
        sb.append("!");

        System.out.println("Thread-Safe String: " + sb.toString());  // Output: Hello World!
    }
}
Enter fullscreen mode Exit fullscreen mode
  • This code is similar to StringBuilder, but StringBuffer is synchronized, making it suitable for multi-threaded environments.

4. Comparing String, StringBuilder, and StringBuffer

This program compares performance between String, StringBuilder, and StringBuffer when performing the same concatenation operation.

public class StringPerformanceComparison {
    public static void main(String[] args) {
        // Using String (Immutable)
        String str = "";
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            str += i;
        }
        long endTime = System.currentTimeMillis();
        System.out.println("String time: " + (endTime - startTime) + "ms");

        // Using StringBuilder (Mutable)
        StringBuilder sb = new StringBuilder();
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            sb.append(i);
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuilder time: " + (endTime - startTime) + "ms");

        // Using StringBuffer (Mutable & Thread-Safe)
        StringBuffer sbf = new StringBuffer();
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            sbf.append(i);
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuffer time: " + (endTime - startTime) + "ms");
    }
}
Enter fullscreen mode Exit fullscreen mode
  • This program shows how much faster StringBuilder and StringBuffer are compared to String when doing many concatenations.

5. Reversing a String using StringBuilder

public class ReverseStringBuilder {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Hello World");
        sb.reverse();

        System.out.println("Reversed String: " + sb.toString());  // Output: dlroW olleH
    }
}
Enter fullscreen mode Exit fullscreen mode
  • The reverse() method of StringBuilder is used to reverse the characters in a string.

These programs should help you refresh your understanding of strings, StringBuilder, and StringBuffer!

. . . . . . . . . . . .
Terabox Video Player