JavaRush /Java Blog /Random EN /Introduction to String, StringBuffer and StringBuilder in...

Introduction to String, StringBuffer and StringBuilder in Java

Published in the Random EN group
There are three classes in Java for working with text data: String , StringBuffer and StringBuilder . Every developer encounters the first one at the very beginning of learning the language. What about the remaining two? What are their differences, and when is it better to use one or another class? In general, the difference between them is small, but it’s better to understand everything in practice :) Introduction to String, StringBuffer and StringBuilder in Java - 1

String class

This class represents a sequence of characters. All string literals defined in programs, such as "This is String" are instances of the String class. String has two fundamental features:
  • this is an immutable class
  • this is final class
In general, the String class cannot have children ( final) and instances of the class cannot be modified after creation ( immutable). This gives the String class several important advantages:
  1. Due to immutability, the hashcode of an instance of the String class is cached. It doesn't need to be evaluated every time because the object's field values ​​will never change after it is created. This gives high performance when using this class as a key for HashMap.

  2. The String class can be used in a multi-threaded environment without additional synchronization.

  3. Another feature of the String class is that it overloads the " +" operator in Java. Therefore, concatenation (addition) of strings is quite simple:

public static void main(String[] args) {
    String command = "Follow" + " " + "the" + " " + "white" + " " + "rabbit";
    System.out.println(command); // Follow the white rabbit
}
Under the hood, string concatenation is performed by the StringBuilder or StringBuffer class (at the discretion of the compiler) and a method append(we'll talk about these classes a little later). If we add instances of the String class with instances of other classes, the latter will be reduced to a string representation:
public static void main(String[] args) {
    Boolean b = Boolean.TRUE;
    String result = "b is " + b;
    System.out.println(result); //b is true
}
This is another interesting property of the String class: objects of any class can be cast to a string representation using the method toString()defined in the class Objectand inherited by all other classes. Often the toString() method on an object is called implicitly. For example, when we display something on the screen or add a String to an object of another class. The String class has one more feature. All string literals defined in Java code, such as "asdf", are cached at compile time and added to the so-called string pool. If we run the following code:
String a = "Wake up, Neo";
String b = "Wake up, Neo";

System.out.println(a == b);
We'll see true in the console because the variables will aactually brefer to the same instance of the String class that was added to the string pool at compile time. That is, different instances of the class with the same value are not created, and memory is saved.

Flaws:

It is not difficult to guess that the String class is needed primarily for working with strings. But in some cases, the above features of the String class can turn from advantages into disadvantages. Once strings are created in Java code, many operations are often performed on them:
  • converting strings to different registers;
  • substring extraction;
  • concatenation;
  • etc.
Let's look at this code:
public static void main(String[] args) {

    String s = " Wake up, Neo! ";
    s = s.toUpperCase();
    s = s.trim();

    System.out.println("\"" + s + "\"");
}
At first glance, it seems that we just translated the line “Wake up, Neo!” to uppercase, removed extra spaces from this string and wrapped it in quotes. In fact, due to the immutability of the String class, as a result of each operation, new string instances are created and old ones are discarded, generating a large amount of garbage. How to avoid wastage of memory?

StringBuffer class

To handle the creation of temporary garbage due to modifications to a String object, you can use the StringBuffer class. This is mutablea class, i.e. changeable. An object of the StringBuffer class can contain a specific set of characters, the length and value of which can be changed by calling certain methods. Let's see how this class works. To create a new object, use one of its constructors, for example:
  • StringBuffer() - will create an empty (no characters) object
  • StringBuffer(String str) - will create an object based on the str variable (containing all the characters of str in the same sequence)
Practice:
StringBuffer sb = new StringBuffer();
StringBuffer sb2 = new StringBuffer("Not empty");
String concatenation via StringBuffer in Java is done using the append. In general, the method appendin the StringBuffer class is overloaded in such a way that it can accept almost any data type:
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer();

    sb.append(new Integer(2));
    sb.append("; ");
    sb.append(false);
    sb.append("; ");
    sb.append(Arrays.asList(1,2,3));
    sb.append("; ");

    System.out.println(sb); // 2; false; [1, 2, 3];
}
The method appendreturns the object on which it was called (like many other methods), which allows it to be called in a “chain”. The example above can be written like this:
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer();

    sb.append(new Integer(2))
            .append("; ")
            .append(false)
            .append("; ")
            .append(Arrays.asList(1,2,3))
            .append("; ");

    System.out.println(sb); // 2; false; [1, 2, 3];
}
The StringBuffer class has a number of methods for working with strings. Let's list the main ones:
  • delete(int start, int end)— deletes a substring of characters starting from position start, endingend
  • deleteCharAt(int index)— deletes the character at positionindex
  • insert(int offset, String str)— inserts a line strat position offset. The method insertis also overloaded and can take different arguments
  • replace(int start, int end, String str)- will replace all characters from position startto position endbystr
  • reverse()— reverses the order of all characters
  • substring(int start)- will return a substring starting at position start
  • substring(int start, int end)- will return a substring starting from position startto positionend
A complete list of methods and constructors is in the official documentation . How do the above methods work? Let's see in practice:
public static void main(String[] args) {
     String numbers = "0123456789";

     StringBuffer sb = new StringBuffer(numbers);

     System.out.println(sb.substring(3)); // 3456789
     System.out.println(sb.substring(4, 8)); // 4567
     System.out.println(sb.replace(3, 5, "ABCDE")); // 012ABCDE56789

     sb = new StringBuffer(numbers);
     System.out.println(sb.reverse()); // 9876543210
     sb.reverse(); // Return the original order

     sb = new StringBuffer(numbers);
     System.out.println(sb.delete(5, 9)); // 012349
     System.out.println(sb.deleteCharAt(1)); // 02349
     System.out.println(sb.insert(1, "One")); // 0One2349
    }

Advantages:

  1. As already mentioned, StringBuffer is a mutable class, so working with it does not create the same amount of memory garbage as with String. Therefore, if a lot of modifications are made to strings, it is better to use StringBuffer.

  2. StringBuffer is a thread safe class. Its methods are synchronized and instances can be used by multiple threads simultaneously.

Flaws:

On the one hand, thread safety is an advantage of the class, and on the other hand, it is a disadvantage. Synchronized methods are slower than non-synchronized methods. This is where StringBuilder comes into play. Let's figure out what kind of Java class it is - StringBuilder, what methods it has and what its features are.

StringBuilder class

StringBuilder in Java is a class that represents a sequence of characters. It is very similar to StringBuffer in every way except thread safety. StringBuilder provides an API similar to StringBuffer's. Let's demonstrate this using an already familiar example, replacing the declaration of variables from StringBufer to StringBuilder:
public static void main(String[] args) {
    String numbers = "0123456789";

    StringBuilder sb = new StringBuilder(numbers);

    System.out.println(sb.substring(3)); //3456789
    System.out.println(sb.substring(4, 8)); //4567
    System.out.println(sb.replace(3, 5, "ABCDE")); //012ABCDE56789

    sb = new StringBuilder(numbers);
    System.out.println(sb.reverse()); //9876543210
    sb.reverse(); // Return the original order

    sb = new StringBuilder(numbers);
    System.out.println(sb.delete(5, 9)); //012349
    System.out.println(sb.deleteCharAt(1)); //02349
    System.out.println(sb.insert(1, "One")); //0One2349
}
The only difference is that StringBuffer is thread safe and all its methods are synchronized, while StringBuilder is not. This is the only feature. StringBuilder in Java is faster than StringBuffer due to the non-synchronization of methods. Therefore, in most cases, except in a multi-threaded environment, it is better to use StringBuilder for a Java program. We summarize everything in a comparative table of the three classes:

String vs StringBuffer vs StringBuilder

String StringBuffer StringBuilder
Changeability Immutable(No) mutable(Yes) mutable(Yes)
Extensibility final(No) final(No) final(No)
Thread safety Yes, due to immutability Yes, due to synchronization No
When to use When working with strings that will rarely be modified When working with strings that will be modified frequently in a multi-threaded environment When working with strings that will be modified frequently in a single-threaded environment
You can study this topic in more detail at the second level of the Java Multithreading quest in the JavaRush course:
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION