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
final
) and instances of the class cannot be modified after creation ( immutable
). This gives the String class several important advantages:
-
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
. -
The String class can be used in a multi-threaded environment without additional synchronization.
-
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 Object
and 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 a
actually b
refer 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.
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 ismutable
a 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)
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 append
in 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 append
returns 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 positionstart
, endingend
deleteCharAt(int index)
— deletes the character at positionindex
insert(int offset, String str)
— inserts a linestr
at positionoffset
. The methodinsert
is also overloaded and can take different argumentsreplace(int start, int end, String str)
- will replace all characters from positionstart
to positionend
bystr
reverse()
— reverses the order of all characterssubstring(int start, int end)
- will return a substring starting from positionstart
to positionend
substring(int start)
- will return a substring starting at position
start
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:
-
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
. -
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 |