|
|
String objects in Java are immutable, so applying any String method to a String object doesn't alter the String object, instead creates a new String object that's value equals the method effect on the String object.
String s = "Hello there";
s.toUpperCase();
System.out.println(s);
This is going to print the original String "Hello there", because what happened here is that we have an object with the value "Hello there" referenced by the variable s, applying the method creates a new String object with the value "HELLO THERE" which is not referenced by any variable, but not changing the old object.
If we want to change the original String, we would write the above code this way:
String s = "Hello there";
s = s.toUpperCase();
System.out.println(s);
Now it will print "HELLO THERE", but how the virtual machine did it? The virtual machine created a new String object with the value "HELLO THERE", and then the reference of the variable s changed from the old String to the new one.
The side effect of this operation is that there are two objects created in the memory, one of them is referenced and the another is not, doing many String operations this way will cause that we have many objects in memory that are not referenced and waiting for the garbage collection to delete them from memory, deleting these objects also takes time, so the application that depends on heavy String operations will lack some performance when String objects are used.
Fortunately Java has two other string related classes, one of them is StringBuffer, which is there since the first version of Java, and the recently added class StringBuilder, both classes are dealing with strings as mutable objects, so applying any method to their objects will change the original object, and won't create a new object, which will add more performance to the application.
StringBuffer and StringBuilder have the same methods, and all methods return the same output for the same input, the difference between them is that StringBuffer is thread safe, but StringBuilder is not, so in your application you will need to decide which class to use, if you have the case that many threads accessing the same string, then you may have the problem of one thread is modifying a string and another one is reading it, in this case using StringBuilder will cause that inconsistent data to be read, so using StringBuffer is the one to use in this case.
If you don't have the case that multiple threads are accessing the same string, it's better to use StringBuilder, StringBuilder was added to Java since version 5, and it has all the StringBuffer methods, the only difference is it's not thread safe, using it will add more performance to your application, because making methods thread safe adds performance cost.
In this lesson all methods will be described in the terms of StringBuffer, but you can use them as is for StringBuilder, because as I said before, the StringBuilder class provides the same set of methods as the StringBuffer class.
|
| Creating StringBuffer objects
|
StringBuffer provides for constructors to create a new object:
StringBuffer sb = new StringBuffer();
StringBuffer sb = new StringBuffer("Hello there!");
StringBuffer sb = new StringBuffer(5);
The above three statements work as follows:
The first one creates a new StringBuffer object with initial capacity of 16 characters.
The second one creates a new StringBuffer from the String object "Hello ther!", the initial capacity of the StringBuffer is 16 characters plus the length of the String argument (12 in this case).
The last one creates a new StringBuffer with initial capacity of 5 characters.
As we can see here that the StringBuffer has a capacity, the StringBuffer is a buffer, and every buffer has a capacity, the capacity is initialized in StringBuffer, and as long as the character sequence contained in the buffer doesn't exceed the capacity, it will not allocate more capacity. If the internal buffer overflows, it's automatically made larger.
The fourth and last constructor accepts a CharSequence as an argument, this is a general case of the second constructor that accepts a String object, because CharSequence is an interface, and the implementing classes are CharBuffer, Segment, String, StringBuffer, and StringBuilder. Any object of these classes can be an argument for this constructor.
StringBuilder s = new StringBuilder("Hello");
StringBuffer sb = new StringBuffer(s);
|
| Investigating the StringBuffer
|
| There are many methods that investigate the characteristics of a StringBuffer object:
capacity(): returns an integer that represents the current capacity of a StringBuffer.
charAt(int index): returns the char value at the specified index.
indexOf(String str): returns an integer that represents the index of first occurrence of the specified substring in the StringBuffer object, -1 if not found.
indexOf(String str, int fromIndex): returns an integer that represents the index of first occurrence of the specified substring in the StringBuffer object starting from the specified index, -1 if not found.
lastIndexOf(String str): returns an integer that represents the index of last occurrence of the specified substring in the StringBuffer object, -1 if not found.
lastIndexOf(String str, int fromIndex): returns an integer that represents the index of last occurrence of the specified substring in the StringBuffer object starting from the specified index, -1 if not found.
length(): returns the length of the StringBuffer (characters count).
|
| Appending characters to StringBuffer
|
|
We can append to the StringBuffer using the method append(), this method comes in 13 flavors, each accepting different arguments (overloading).
The method argument can be any java literal data type:
boolean, char, double, float, int, and long
StringBuffer sb = new StringBuffer("Hello ");
sb.append(5);
The new object will be "Hello 5"
Also the argument can be:
String, StringBuffer (StringBuilder in case of StringBuilder class), char[], part of a char[], CharSequence, part of a CharSequence.
StringBuffer sb = "Hello ";
char [] c = {'J', 'a', 'y', 'S', 'm', 'i', 't', 'h', 'J', 'a', 'y'};
sb.append(c, 3, 5);
The new object will be "Hello Smith", part of the char array here was appended, the method arguments are:
c: the array character.
3: the index of the first char to append.
5: the number of chars to append.
The last flavor of the arguments is an object; the method here appends the String representation of the object to the original object:
StringBuffer sb = new StringBuffer("Today is “");
java.util.Date d = new java.util.Date();
sb.append(d);
The resulting object can be something like "Today is Mon Apr 30 18:20:20 2007"
|
| Inserting characters inside the StringBuffer
|
| This is different than appending the characters to the StringBuffer, here we insert the characters at any index of the StringBuffer, not only at the end.
To insert character inside the StringBuffer, the method insert() is used, this method comes in 11 flavors, each accepting different arguments (overloading):
The method argument can be any java literal data type:
boolean, char, double, float, int, and long
StringBuffer sb = new StringBuffer("Speed is kB/s");
sb.insert(9, 9.5);
The output will be "Speed is 9.5 kB/s", the method accepts 2 arguments, the first is the index of where to insert the characters, and the second argument is the characters to insert.
Also the argument can be:
String, StringBuffer (StringBuilder in case of StringBuilder class), char[], part of a char[], CharSequence, part of a CharSequence.
The last flavor of the argument is an object; the method here inserts the String representation of the object to the original object.
|
| Deleting characters of StringBuffer
|
| To delete characters from the StringBuffer, we have two methods:
delete(int start, int end): removes characters of the StringBuffer starting from the specified start index to the specified end index.
deleteCharAt(int index): removes the character of the StringBuffer at the specified index.
|
| Other StringBuffer methods
|
| Replace(int start, int end, String str): replaces the characters in the StringBuffer starting from the specified start index to the specified end index with the specified string.
reverse(): reverses the StringBuffer.
setCharAt(int index, char ch): sets the char at the specified index to the specified chr.
substring(int start): returns a String that contains the characters of the StringBuffer starting from the specified index.
substring(int start, int end): returns a String that contains the characters of the StringBuffer starting from the specified start index to the specified end index.
toString(): returns a String representing the StringBuffer.
trimToSize(): reduces the storage used by the StringBuffer by adjusting the buffer size to be equaled to the number of characters in the StringBuffer.
|
|