Explore String, StringBuilder, and StringBuffer in Java

preface

I believe that String is one of the most frequently used classes in Java, and it is also a favorite question in interviews with major companies. Today, let's learn about String, StringBuilder and StringBuffer, analyze their similarities and differences and understand the applicable scenarios of each class

1, String class

  • The value of String is immutable, which leads to the generation of new String objects every time you operate on String, which is not only inefficient, but also a large waste of limited memory space.
  • Partial source code:
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;
......
  • As can be seen from the above:

  • String class is final, which means that string class cannot be inherited, and its member methods are final by default. In Java, the class modified by final is not allowed to be inherited, and the member methods in this class are all final methods by default. Set the method to final only when it is determined that you do not want the method to be overwritten.

  • Partial method source code

    public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }

    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }

    public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */

            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }
  • It can be seen from the above three methods that substring, concat or replace operations are not performed on the original string, but a new string object is regenerated. That is, after these operations, the original string has not been changed.
  • Again, any change to the String object will not affect the original object, and any related change operation will generate a new object.

2, StringBuffer

  • StringBuffer is a variable class and thread safe string operation class. Any operation on the string it points to will not produce a new object.
  • Each StringBuffer object has a certain buffer capacity. When the string size does not exceed the capacity, no new capacity will be allocated. When the string size exceeds the capacity, the capacity will be automatically increased.
StringBuffer buf=new StringBuffer(); //Allocate a 16 byte character buffer
StringBuffer buf=new StringBuffer(512); //Allocate 512 byte character buffer
StringBuffer buf=new StringBuffer("this is a test")//The string is stored in the buffer, and an empty buffer of 16 bytes is reserved after it
  • Partial source code:
public StringBuffer() {
        super(16);
    }

   public StringBuffer(int capacity) {
        super(capacity);
    }
       public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }

  • Partial method source code
    public synchronized String substring(int start) {
        return substring(start, count);
    }

    public synchronized StringBuffer replace(int start, int end, String str) {
        toStringCache = null;
        super.replace(start, end, str);
        return this;
    }
    public synchronized String substring(int start, int end) {
        return super.substring(start, end);
    }
  • It can be seen from the above method that both substring operation and replace operation are performed on the original string, and synchronized is thread safe, but the performance is higher than StringBuffer because it is not synchronized.

3, StringBuilder

  • StringBuilder is a variable class and thread unsafe string operation class. Any operation on the string it points to will not produce new objects.
  • Each StringBuffer object has a certain buffer capacity. When the string size does not exceed the capacity, no new capacity will be allocated. When the string size exceeds the capacity, the capacity will be automatically increased.
StringBuilder buf=new StringBuilder(); //Allocate a 16 byte character buffer
StringBuilder buf=new StringBuilder(512); //Allocate 512 byte character buffer
StringBuilder buf=new StringBuilder("this is a test")//The string is stored in the buffer, and an empty buffer of 16 bytes is reserved after it
  • Partial source code:
  public StringBuilder() {
        super(16);
    }
    public StringBuilder(int capacity) {
        super(capacity);
    }

    public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }
  • Partial method source code
    public StringBuilder replace(int start, int end, String str) {
        super.replace(start, end, str);
        return this;
    }
    
  • It can be seen from the above method that the replace operation is performed on the original string, and it is thread unsafe if it is not synchronized, but it also leads to performance ratio because it is not synchronized.

4, Common methods

String common methods

//Length() the length of the string
String a = "Hello Word!";
System.out.println(a.length);
//The output is a string length of 10. 

// charAt() intercepts a character
String a = "Hello Word";
System.out.println(a.charAt(1));
//The output result is the character e with subscript 1 of string a.

// getchars () intercepts multiple characters and receives them by other strings
String a = "Hello Word";
char[] b = new char[10];
a.getChars(0, 5, b, 0);
System.out.println(b);
//The output result is Hello, where the first parameter 0 is the initial subscript (int sourceStart) of the string to be intercepted,
//The second parameter 5 is the next subscript (int sourceEnd) after the end of the string to be intercepted, that is, the actually intercepted subscript is int sourceEnd-1,
//The third parameter is the received string (char target []), and the last parameter is the starting position of the received string.

//getBytes() turns the string into a byte array
String a = "Hello Word";
byte b[] = a.getBytes();
System.out.println(new String(b));
//The output result is the byte array of Hello Word. 

// toCharArray() turns a string into a character array
String a = "Hello Word";
char[]b = a.toCharArray();
System.out.println(b);  
//The output is a Hello Word character array.

// equals() and equalsIgnoreCase() compare whether two strings are equal. The former is case sensitive and the latter is not
String a = "Hello Word";
String b = "hello word";
System.out.println(a.equals(b));
System.out.println(a.equalsIgnoreCase(b));  
//The output result is that the first one is false and the second one is true.

// startsWith() and endsWith() determine whether a string starts or ends with a specific character
String a = "Hello Word";
System.out.println(a.startsWith("ee"));  
System.out.println(a.endsWith("rd"));
//The first output is false and the second is true.

// toUpperCase() and toLowerCase() convert strings to uppercase or lowercase
String a = "Hello Word";
System.out.println(a.toUpperCase());
System.out.println(a.toLowerCase());
//The first output is "Hello word" and the second is "Hello word".

// concat() connects two strings
String a = "Hello Word";
String b = "Hello";
System.out.println(b.concat(a));
//The output is "Hello Word".

// trim() removes the start and end spaces
String a = "    Hello Word   ";
System.out.println(a.trim());
//The output is "Hello Word".

//substring() intercepts string
String a = "Hello Word";
System.out.println(a.substring(0, 5));
System.out.println(a.substring(6));
//The first output result is "Hello", and the first parameter 0 (beginIndex) is the starting position of interception,
//The second parameter 5 (endIndex) is the position where the interception ends, the second output result is "Word", and the parameter 6 (beginIndex) is the position where the interception starts.

//indexOf() and lastIndexOf(), the former is where the character or string is found for the first time, and the latter is where the character or string is found for the last time
String a = "Hello Word";
System.out.println(a.indexOf("o"));
System.out.println(a.lastIndexOf("o"));
//The first output is 4, which is the subscript of o for the first time, and the second is 7, which is the subscript of o for the last time.

//compareTo() and compareToIgnoreCase() compare the size of two strings in dictionary order. The former is case sensitive and the latter is not
String a = "Hello Word";
String b = "hello word";
System.out.println(a.compareTo(b));
System.out.println(a.compareToIgnoreCase(b)); 
//The first output result is - 32 and the second is 0. The two strings have the same size in the dictionary order and return 0.

// replace() replace
String a = "Hello Word";
String b = "Hello";
System.out.println(a.replace(a, b));
System.out.println(a.replace(a, "HELLO WORD"));
System.out.println(b.replace("you", "everybody"));
//The first output is "hello", the second is "HELLO WORD", and the third is "Hello everyone".

StringBuffer common methods

StringBuffer tmp = new StringBuffer("cba");

//append(String s): appends the specified string to this character sequence.
System.out.println("append():\t" + tmp.append("|append(a)"));

//Reverse(): replaces this character sequence with its inverted form.
System.out.println("reverse():\t" + tmp.reverse());

//delete(int start, int end): remove the characters in the substring of this sequence.
System.out.println("delete():\t" + tmp.delete(0, 3));

//insert(int offset, int i): insert the string representation of the int parameter into this sequence.
System.out.println("insert():\t" + tmp.insert(0, "|insert|"));

//replace(int start, int end, String str): replace the characters in the substring of this sequence with the characters in the given String.
System.out.println("replace():\t" + tmp.replace(0, 2, "(a)")); 

StringBuilder common methods

  • Similar to StringBuffer

summary

  • Generally, the speed changes from fast to slow: StringBuilder > StringBuffer > string. This comparison is relative, not absolute.
  • If you want to manipulate a small amount of data, use String
  • Single thread operation string buffer to operate a large amount of data StringBuilder
  • Multithreading operation string buffer to operate a large amount of data

Keywords: Java string

Added by jamkelvl on Sat, 19 Feb 2022 04:28:58 +0200