Hello people…! This is a new post in Java Tutorials – String, StringBuffer and StringBuilder in Java. In this post, I will talk about some basics about Strings in Java. Why basics…? Well, there is a lot in Java when it comes to Strings, which we can’t understand right now due to lack of knowledge. But, on the other hand, these are so basic elements of simple programs, that we can hardly write any useful code without these. So, I will cover only what is required to programs involving good computation, so that you will be able to practice Java writing those programs which you wrote to practise C.
Strings in Java
First of all, to learn Strings in Java… You must forget whatever you learnt about strings in C…! This is because, a String in Java is not exactly treated as an array of characters terminated by a null character..! No..! String in Java is actually an object of the String Class, which is in the java.lang package, or library. But, we can use it fairly as we use strings in C++ (#include <string>). If you know only C, then watch closely..!
String name = "Albus Dumbledore";
This is how we create a String in Java. Here, the variable name, is called an Object Reference. As the name suggests, object reference, it points to an object. The object reference here is of the data type String, which is a class. We will talk a lot about a class later, but for now, think of it as a struct where we can have methods, hence, a user defined data type, here defined by Java for you. Now, the variable name is now pointing to an object of String Class, which has the data “Albus Dumbledore”.
So, when the above line is executed, we don’t get an array of characters, but instead, we get one chunk of memory where the string is stored.
Now, how would we access the variables inside a struct..? We would use the dot operator (struct.variable). Similarly, we use the dot operator, to access the variables and methods of the String Class. Well, let’s proceed with a familiar example of a C struct.
struct Person { char * name; char * phone; char * email; int age; }; int main() { struct Person harry; harry.name = "Harry Potter"; harry.phone = "9999999999"; harry.email = "harrypotter@hogwarts.com"; harry.age = 10; return 0; }
This is how we would create a variable of type struct Person and use its members. In the same fashion, we will use the members of String Class, but this time, it will be functions, not variables (not that we can’t have variables)..!
public class JavaStrings { public static void main(String[] args) { String name = "Albus Dumbledore"; // Prints length of String System.out.println(name.length()); // 16 // Prints the last character of String -> e System.out.println(name.charAt(name.length() - 1)); // Returns index of the 1st occurence System.out.println(name.indexOf("bus")); // 2 // Returns the substring from startIndex - endIndex // Here, returns the first word -> Albus System.out.println( name.substring(0, name.indexOf(' '))); // Another Example String plan = "Plan you work, and work your plan"; // false, as it starts with "Plan" not "plan" System.out.println(plan.startsWith("plan")); // true, as it ends with "plan" System.out.println(plan.endsWith("plan")); } }
As you can see, when we use the object reference, name or plan, we can access the various functions provided to us by String Class. All these methods are accessed by the object reference. I’ve used a lot of functions in the program, let’s look at them in a little more detail –
- length() – This function returns an int, which is the length of the string –
System.out.println(name.length());
But, which string…? The one name is pointing to..! If the same function were called on another object reference, it would return the length of that string, as in –
String name = "Albus Dumbledore"; String plan = "Plan you work, and work your plan"; System.out.println(name.length()); // 16 System.out.println(plan.length()); // 33
- charAt(int index) – This function, as the name suggests, returns the character the the given index –
System.out.println(name.charAt(name.length() - 1));
So, the return type is char. Argument must be zero indexed. But what if we give an invalid index. What would happen to the code below..?
public static void main(String[] args) { String name = "Albus Dumbledore"; System.out.println(name.charAt(100)); }
This would cause a runtime error, or famously called as an Exception..!
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 100 at java.lang.String.charAt(String.java:646) at test.main(test.java:7) Java Result: 1
So, the StringIndexOutOfBoundsException is thrown at runtime.
- indexOf(String str) – This function returns an int, which is the first occurrence, of the string provided as argument –
System.out.println(name.indexOf("bus")); // 2
If the search fails, -1 is returned. The argument can be a char also, as we searched for first space while printing the first word.
- substring(int startIndex, int endIndex) – This function returns a substring from the string in the object, from a specified startIndex to an endIndex –
//Returns "Albus" System.out.println(name.substring(0, 4));
If either of the arguments are given improperly, the familiar StringIndexOutOfBoundsException is thrown at runtime.
- startsWith(String prefix) & endsWith(String suffix) – These two functions check if the string in the object have the mentioned prefix or suffix –
System.out.println(plan.startsWith("plan")); System.out.println(plan.endsWith("plan"));
The return type of this function is boolean, so, it returns true if the prefix or suffix is present, otherwise, false.
These were just a few of the many functions that Java provides. We will have a brief note about a few more of others later.
Basic Operations on Strings in Java
- Concatenation – We use the addition operator, ‘+’ to concatenate Strings in Java. This is much like the modern programming languages. String Class does provide a method, but this is the most compact way of concatenating strings.
public class ThatName { public static void main(String[] args) { String name = "Albus "; name = name + "Percival "; name = name + "Wulfric "; name += "Brian "; name += "Dumbledore!"; System.out.println("The name is - " + name); } }
The other way, is to use the concat() function of the String Class. It returns the concatenated String, which must be assigned back.
public class IWishTheLegendContinued { public static void main(String[] args) { String name = "Albus "; name = name.concat("Severus "); name = name.concat("Potter"); System.out.println(name +"! You've been named" + " after two Headmasters of Hogwarts!"); } }
Harry Potter fans…! Please continue the dialogue for me..!! 😀
- Equality – Beginners make a common mistake of comparing two strings using “==”. This does not work properly..! We must always use the equals() method of the String class to compare two strings. The data type of the argument is something I’ll reserve for later..! But, remember that this is how we compare Strings –
public class DeadlyDuo { public static void main(String[] args) { String fred = "Tall n' Brave"; String george = "Tall "; george += "n' Brave"; if (fred.equals(george)) { System.out.println("Equal"); } } }
- Comparision – We use the compareTo() function in the String Class to lexicographically compare two strings –
public class IssIssIppiWhatever { public static void main(String[] args) { String str1 = "Missouri"; String str2 = "Mississippi"; if (str1.compareTo(str2) == 0) { System.out.println("Equal"); } else if (str1.compareTo(str2) < 0) { System.out.println(str1); } else { System.out.println(str2); } } }
As you can see, it compares two strings and returns an integer –
- Less than zero – If the argument is lexicographically smaller than the string in object reference.
- Equal to zero – If both strings are lexicographically equal.
- Greater than zero – If the argument is lexicographically greater than the string in object reference.
Mutable Strings
Strings in Java are actually immutable in nature. It means that, they cannot be modified or, they are read-only. We cannot change the content inside them. Then how can we create strings where we can actually manipulate them..? We can do so, by creating objects of –
- StringBuffer Class
- StringBuilder Class
Till now we have created strings using the String Class. But as they are immutable, we will create strings using the other classes. Let’s use the StringBuffer Class –
public class LikeFatherLikeSon { public static void main(String[] args) { StringBuffer father, son; father = new StringBuffer("James Potter"); son = father.replace(0, father.indexOf(" "), "Harry"); System.out.println(son); } }
As you can see, these strings can be modified. We use the various methods provided in the StringBuffer Class to manipulate them. Some of them are discussed in the next section.
Methods in StringBuffer Class
Method Signature | Short Description |
---|---|
StringBuffer append(String str) | Appends, adds it to the end, of the argument string. |
char charAt(int index) | Retrieves the character at the index in the range [0, length – 1] |
StringBuffer delete(int startIndex, int endIndex) | Deletes the characters from the string in the range [startIndex, endIndex) |
StringBuffer deleteCharAt(int index) | Deletes the character from the string at the specified index. |
int indexOf(String str) | If found, returns the index of the first occurrence of the string str, otherwise, returns -1. |
StringBuffer insert(int offset, String str) | Inserts the string str at an offset, or, inserts it in between characters at index – (offset – 1) and offset |
int lastIndexOf(String str, int startIndex) | If found, returns the index last occurrence of str from startIndex (optional). Call lastIndexOf(“”) returns the string length. |
int length() | Returns the length of the string. |
StringBuffer replace(int startIndex, int endIndex, String str) | Replaces the [startIndex, endIndex) portion of the string with str. |
StringBuffer reverse() | Returns the string with the character sequence reversed. |
void setCharAt(int index, int newChar) | Replaces the character at index to newChar |
String substring(int startIndex, int endIndex) | Returns an object of String Class which is a substring of the original string in the range [startIndex, endIndex). The parameter endIndex is optional. |
Difference between StringBuffer and StringBuilder
The same methods which are provided by the StringBuffer Class are also provided by the StringBuilder Class (of course they differ in the return types), but with a small twist. Well, you need to know a little Multi-threading to understand this properly, but it doesn’t harm to learn them now. We will re-visit this topic again, but for now, I wan’t you to be ready if anybody asks the difference.
StringBuffer | StringBuilder |
---|---|
All methods in StringBuffer are synchronized. Which means that they are thread-safe. By thread-safe, we mean that no two threads can simultaneously access the method of an object of StringBuffer Class. | Methods are not synchronized. Which means that they are not thread-safe. So, using StringBuilder in a multi-threading environment can cause data corruption due to concurrency. |
Being synchronized, they are slow. This is because of the thread safety. | Faster than StringBuffer because they don’t carry a burden on synchronization. |
But, in a single-threading environment, these two should deliver fairly equal performance. So this choice is left to the programmer. The reference snips are taken from the original java.lang.StringBuffer and java.lang.StringBuilder Class provided by Java, as viewed from NetBeans IDE. I don’t want you to worry about what you don’t understand. All I want you to notice in those snips is the presence and absence of the keyword synchronized. What does it do..? We’ll get to it later.
Behind the Curtains !
This is an advanced discussion about the internals of String, StringBuilder, StringBuffer class. Beginners… Feel free to skip this….!
Well, so far we talked about Strings as an object, a chunk of memory, not as an array of characters. But the thing is that, internally, String is an array of characters. In the String class, we have a member which is an array of characters. And this member is a constant for the String Class. So, its like…. If we put this in C terms, it would look like –
struct String { const char value[10]; };
But it is not as simple as it looks, arrays function differently in Java. In fact, if Oracle sees me comparing String Class with that piece of C code, it might say, “If you delete that now, that’ll be the end of it. I will not look for you, I will not pursue you. But if you don’t, I will look for you, I will find you, and I will kill you.” 😛
To get an idea, this is what happening in the String Class –
As you can see –
- There’s an array of name value.
- It is declared final, means that it is constant.
- String Class is final too. So, StringBuffer and StringBuilder are not subclasses of String Class..!
- The array of characters is private. So, internally String is an array, but we don’t get to see it. This…! This is exactly what Encapsulation is..!! Hiding the implementation…! 😉
So, that’s Java’s little back game, it is operating on an array..! So, when we call length() method, this is what it does –
And all the methods operate on this array and return the results if any or throw exceptions accordingly. One last example to make things clear. This is the implementation of the charAt() method –
When it comes to the StringBuffer and StringBuilder Classes, they both inherit from java.lang.AbstractStringBuilder Class..! There, in the abstract class, the character array is defined, which these classes inherit. This is the definition of the AbstractStringBuilder Class –
As you can see –
- The class is defined as abstract.
- It has a member, value, which is an array of characters.
- The array is not final.
- Instead of relying on value.length, it has a variable count, which stores the characters used
Why is using another variable..? Well… These strings have the notion of capacities and actual sizes. One last thing..! StringBuilder and StringBuffer are final classes, just like many other classes in Java Library.
Summary
- Strings in Java are objects of String Class.
- Strings created using String Class are immutable. They cannot be modified.
- We create mutable strings using StringBuffer and StringBuilder classes. The syntax is –
StringBuffer good = new StringBuffer("Harry Potter"); StringBuilder evil = new StringBuilder("Tom Riddle");
- Methods in StringBuffer are synchronized, where as methods in StringBuilder are not.
- StringBuilder gives a better performance than StringBuffer.
- Internally, the String classes operate on a character array.
This post was to help you with String in Java. I hope it helped you. If you have anything to ask about this topic, feel free to comment..! Keep practising..! Happy Coding..! 😀
3 thoughts on “Java Tutorials – String, StringBuffer and StringBuilder in Java”
So many tutorials with some typical examples. First time i found a material really
helpful with proper explanation about String Buffer and Builder class. Thanks.
Thank you..! 🙂 … I’m glad I could help… 😀