String
is a class built into the Java language defined in the java.lang
package. It represents character strings. Strings are ubiquitous in Java. Study the String
class and its methods carefully. It will serve you well to know how to manipulate them skillfully. String literals in Java programs, such as "abc", are implemented as instances of this class like this:
|
Code section 3.81: String example.
String str = "This is string literal";
|
On the right hand side a String object is created represented by the string literal. Its object reference is assigned to the str
variable.
Strings are immutable; that is, they cannot be modified once created. Whenever it looks as if a String object was modified actually a new String object was created. For instance, the String.trim()
method returns the string with leading and trailing whitespace removed. Actually, it creates a new trimmed string and then returns it. Pay attention on what happens in Code section 3.82:
|
Code section 3.82: Immutability.
String badlyCutText = " Java is great. ";
System.out.println(badlyCutText);
badlyCutText.trim();
System.out.println(badlyCutText);
|
|
|
Output for Code section 3.82
Java is great.
Java is great.
|
|
The trim()
method call does not modify the object so nothing happens. It creates a new trimmed string and then throws it away.
|
Code section 3.83: Assignment.
String badlyCutText = " Java is great. ";
System.out.println(badlyCutText);
badlyCutText = badlyCutText.trim();
System.out.println(badlyCutText);
|
|
|
Output for Code section 3.83
Java is great.
Java is great.
|
|
The returned string is assigned to the variable. It does the job as the trim()
method has created a new String
instance.
The Java language provides special support for the string concatenation with operator +
:
|
Code section 3.84: Examples of concatenation.
System.out.println("First part");
System.out.println(" second part");
String str = "First part" + " second part";
System.out.println(str);
|
|
|
Output for Code section 3.84
First part
second part
First part second part
|
|
The concatenation is not always processed at the same time. Raw string literals concatenation is done at compile time, hence there is a single string literal in the byte code of the class. Concatenation with at least one object is done at runtime.
+
operator can concatenate other objects with strings. For instance, integers will be converted to strings before the concatenation:
|
Code section 3.85: Concatenation of integers.
System.out.println("Age=" + 25);
|
|
|
Output for Code section 3.85
Age=25
|
|
Each Java object has the String toString()
inherited from the Object
class. This method provides a way to convert objects into String
s. Most classes override the default behavior to provide more specific (and more useful) data in the returned String
:
|
Code section 3.86: Concatenation of objects.
System.out.println("Age=" + new Integer(31));
|
|
|
Output for Code section 3.86
Age=31
|
|
Using StringBuilder/StringBuffer to concatenate strings
[edit | edit source]
Remember that String
objects are immutable objects. Once a String
is created, it can not be modified, takes up memory until garbage collected. Be careful of writing a method like this:
|
Code section 3.87: Raw concatenation.
public String convertToString(Collection<String> words) {
String str = "";
// Loops through every element in words collection
for (String word : words) {
str = str + word + " ";
}
return str;
}
|
On the +
operation a new String
object is created at each iteration. Suppose words
contains the elements ["Foo", "Bar", "Bam", "Baz"]
. At runtime, the method creates thirteen String
s:
""
"Foo"
" "
"Foo "
"Foo Bar"
" "
"Foo Bar "
"Foo Bar Bam"
" "
"Foo Bar Bam "
"Foo Bar Bam Baz"
" "
"Foo Bar Bam Baz "
Even though only the last one is actually useful.
To avoid unnecessary memory use like this, use the StringBuilder
class. It provides similar functionality to String
s, but stores its data in a mutable way. Only one StringBuilder
object is created. Also because object creation is time consuming, using StringBuilder
produces much faster code.
|
Code section 3.88: Concatenation with StringBuilder .
public String convertToString(Collection<String> words) {
StringBuilder buf = new StringBuilder();
// Loops through every element in words collection
for (String word : words) {
buf.append(word);
buf.append(" ");
}
return buf.toString();
}
|
As StringBuilder
isn't thread safe (see the chapter on Concurrency) you can't use it in more than one thread. For a multi-thread environment, use StringBuffer
instead which does the same and is thread safe. However, StringBuffer
is slower so only use it when it is required. Moreover, before Java 5 only StringBuffer
existed.
Comparing strings is not as easy as it may first seem. Be aware of what you are doing when comparing String
's using ==
:
|
Code section 3.89: Dangerous comparison.
String greeting = "Hello World!";
if (greeting == "Hello World!") {
System.out.println("Match found.");
}
|
|
|
Output for Code section 3.89
Match found.
|
|
The difference between the above and below code is that the above code checks
to see if the String
's are the same objects in memory which they are. This is as a result of the fact that
String
's are stored in a place in memory called the String Constant Pool. If the new
keyword is not explicitly used when
creating the String
it checks to see if it already exists in the Pool and uses the existing one. If it does not exist, a new Object is created. This is what allows Strings to be immutable in Java.
To test for equality, use the equals(Object)
method inherited by every class and defined by String
to return true
if and only if the object passed in is a String
contains the exact same data:
|
Code section 3.90: Right comparison.
String greeting = "Hello World!";
if (greeting.equals("Hello World!")) {
System.out.println("Match found.");
}
|
|
|
Output for Code section 3.90
Match found.
|
|
Remember that the comparison is case sensitive.
|
Code section 3.91: Comparison with lowercase.
String greeting = "Hello World!";
if (greeting.equals("hello world!")) {
System.out.println("Match found.");
}
|
|
|
Output for Code section 3.91
|
|
To order String
objects, use the compareTo()
method, which can be accessed wherever we use a String datatype. The compareTo()
method returns a negative, zero, or positive number if the parameter is less than, equal to, or greater than the object on which it is called. Let's take a look at an example:
|
Code section 3.92: Order.
String person1 = "Peter";
String person2 = "John";
if (person1.compareTo(person2) > 0) {
// Badly ordered
String temp = person1;
person1 = person2;
person2 = temp;
}
|
The code section 3.92 is comparing the String variable person1
to person2
. If person1
is different even in the slightest manner, we will get a value above or below 0 depending on the exact difference. The result is negative if this String object lexicographically precedes the argument string. The result is positive if this String object lexicographically follows the argument string. Take a look at the Java API for more details.
Sometimes it is useful to split a string into separate strings, based on a regular expressions. The String
class has a split()
method, since Java 1.4, that will return a String array:
|
Code section 3.93: Order.
String person = "Brown, John:100 Yonge Street, Toronto:(416)777-9999";
...
String[] personData = person.split(":");
...
String name = personData[0];
String address = personData[1];
String phone = personData[2];
|
Another useful application could be to split the String text based on the new line character, so you could process the text line by line.
It may also be sometimes useful to create substrings, or strings using the order of letters from an existing string. This can be done in two methods.
The first method involves creating a substring out of the characters of a string from a given index to the end:
|
Code section 3.94: Truncating string.
String str = "coffee";
System.out.println(str.substring(3));
|
|
|
Output for Code section 3.94
fee
|
|
The index of the first character in a string is 0.
By counting from there, it is apparent that the character in index 3 is the second "f" in "coffee". This is known as the beginIndex
. All characters from the beginIndex
until the end of the string will be copied into the new substring.
The second method involves a user-defined beginIndex
and endIndex
:
|
Code section 3.95: Extraction of string.
String str = "supporting";
System.out.println(str.substring(3, 7));
|
|
|
Output for Code section 3.95
port
|
|
The string returned by substring()
would be "port".
s
|
u
|
p
|
p
|
o
|
r
|
t
|
i
|
n
|
g
|
0
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
Please note that the endIndex is not inclusive. This means that the last character will be of the index endIndex-1
. Therefore, in this example, every character from index 3 to index 6, inclusive, was copied into the substring.
|
It is easy to mistake the method substring() for subString() (which does not exist and would return with a syntax error on compilation). Substring is considered to be one word. This is why the method name does not seem to follow the common syntax of Java. Just remember that this style only applies to methods or other elements that are made up of more than one word.
|
The String
class also allows for the modification of cases. The two methods that make this possible are toLowerCase()
and toUpperCase()
.
|
Code section 3.96: Case modification.
String str = "wIkIbOoKs";
System.out.println(str.toLowerCase());
System.out.println(str.toUpperCase());
|
|
|
Output for Code section 3.96
wikibooks
WIKIBOOKS
|
|
These methods are useful to do a search which is not case sensitive:
|
Code section 3.97: Text search.
String word = "Integer";
String text = "A number without a decimal part is an integer."
+ " Integers are a list of digits.";
...
// Remove the case
String lowerCaseWord = word.toLowerCase();
String lowerCaseText = text.toLowerCase();
// Search
int index = lowerCaseText.indexOf(lowerCaseWord);
while (index != -1) {
System.out.println(word
+ " appears at column "
+ (index + 1)
+ ".");
index = lowerCaseText.indexOf(lowerCaseWord, index + 1);
}
|
|
Output for Code section 3.97
Integer appears at column 38.
Integer appears at column 47.
|
Test your knowledge
Question 3.12: You have mail addresses in the following form: <firstName>.<lastName>@<companyName>.org
Write the String getDisplayName(String)
method that receives the mail string as parameter and returns the readable person name like this: LASTNAME Firstname
Answer
|
Answer 3.12: getDisplayName()
public static String getDisplayName(String mail) {
String displayName = null;
if (mail != null) {
String[] mailParts = mail.split("@");
String namePart = mailParts[0];
String[] namesParts = namePart.split("\\.");
// The last name
String lastName = namesParts[1];
lastName = lastName.toUpperCase();
// The first name
String firstName = namesParts[0];
String firstNameInitial = firstName.substring(0, 1);
firstNameInitial = firstNameInitial.toUpperCase();
String firstNameEnd = firstName.substring(1);
firstNameEnd = firstNameEnd.toLowerCase();
// Concatenation
StringBuilder displayNameBuilder = new StringBuilder(lastName).append(" ").append(firstNameInitial).append(firstNameEnd);
displayName = displayNameBuilder.toString();
}
return displayName;
}
|
- We only process non null strings,
- We first split the mail into two parts to separate the personal information from the company information and we keep the name data,
- Then we split the name information to separate the first name from the last name. As the
split()
method use regular expression and .
is a wildcard character, we have to escape it (\.
). However, in a string, the \
is also a special character, so we need to escape it too (\\.
),
- The last name is just capitalized,
- As the case of all the first name characters will not be the same, we have to cut the first name. Only the first name initial will be capitalized,
- Now we can concatenate all the fragments. We prefer to use a
StringBuilder
to do that.