4.1. Welcome to the world of the String class

[9.2] Create and manipulate strings

[3.2] Test equality between Strings and other objects using == and equals()

In this section, we’ll cover the class String defined in the Java API in the java.lang package. The String class represents character strings. We’ll create objects of the class String and work with its commonly used methods, including indexOf(), substring(), replace(), charAt(), and others. You’ll also learn how to determine the equality of two String objects.

The String class is perhaps the most-used class in the Java API. You’ll find instances of this class being used by every other class in the Java API. How many times do you think you’ve used the class String? Don’t answer that question—it’s like trying to count your hair.

Although many developers find the String class to be one of the simplest to work with, this perception can be deceptive. For example, in the String value "Shreya", at which index do you think r is stored—second or third? The correct answer is second because the first letter of a String is stored at index 0 and not index 1. You’ll learn many other facts about the String class in this section.

Let’s start by creating new objects of this class.

4.1.1. Creating String objects

You can create objects of the class String by using the new operator or by using String literal values (values within double quotes). You can assign a String literal value to a String reference variable by using the assignment operator (=). But you may have noticed a big difference in how these objects are stored and referred to by Java.

Let’s create two String objects with the value "Paul" using the operator new:

Figure 4.1 illustrates the previous code.

Figure 4.1. String objects created using the operator new always refer to separate objects, even if they store the same sequence of characters.

In the previous code, a comparison of the String reference variables str1 and str2 prints false. The operator == compares the addresses of the objects referred to by the variables str1 and str2. Even though these String objects store the same sequence of characters, they refer to separate objects stored at separate locations.

Let’s initialize two String variables with the value "Harry" using the assignment operator (=). Figure 4.2 illustrates the variables str3 and str4 and the objects referred to by these variables.

Figure 4.2. String objects created using the assignment operator (=) may refer to the same object if they store the same sequence of characters.

In the preceding example, the variables str1 and str2 referred to different String objects, even if they were created using the same sequence of characters. In the case of variables str3 and str4, the objects are created and stored in a pool of String objects. Before creating a new object in the pool, Java searches for an object with similar contents. When the following line of code executes, no String object with the value "Harry" is found in the pool of String objects:

String str3 = "Harry";

As a result, Java creates a String object with the value "Harry" in the pool of String objects referred to by the variable str3. This action is depicted in figure 4.3.

Figure 4.3. The sequence of steps that executes when Java is unable to locate a String in a pool of String objects

When the following line of code executes, Java is able to find a String object with the value "Harry" in the pool of String objects:

String str4 = "Harry";

Java doesn’t create a new String object in this case, and the variable str4 refers to the existing String object "Harry". As shown in figure 4.4, both variables str3 and str4 refer to the same String object in the pool of String objects.

Figure 4.4. The sequence of actions that executes when Java locates a String in the pool of String objects

You can also create a String object by enclosing a value within double quotes ("):

These values are reused from the String constant pool if a matching value is found. If a matching value isn’t found, the JVM creates a String object with the specified value and places it in the String constant pool:

String morning1 = "Morning";
System.out.println("Morning" == morning1);

Compare the preceding example with the following example, which creates a String object using the operator new and (only) double quotes and then compares their references:

The preceding code shows that object references of String objects that exist in the String constant pool and object references of String objects that don’t exist in the String constant pool don’t refer to the same String object, even if they define the same String value.

Note

The terms String constant pool and String pool are used interchangeably and refer to the same pool of String objects. Because String objects are immutable, the pool of String objects is also called the String constant pool. You may see either of these terms on the exam.

You can also invoke other overloaded constructors of the class String to create its objects by using the operator new:

You can also create objects of String using the classes StringBuilder and StringBuffer:

Because String is a class, you can assign null to it, as shown in the next example:

Exam Tip

The default value for String is null.

Counting String objects

To test your understanding of the various ways in which a String object can be created, the exam may question you on the total number of String objects created in a given piece of code. Count the total number of String objects created in the following code, assuming that the String constant pool doesn’t define any matching String values:

I’ll walk through the code with you step by step to calculate the total number of String objects created:

  • The code at creates a new String object with the value "Summer". This object is not placed in the String constant pool.
  • The code at creates a new String object with the value "Summer" and places it in the String constant pool.
  • The code at doesn’t need to create any new String object. It reuses the String object with the value "Summer" that already existed in the String constant pool.
  • The code at creates a new String object with the value "autumn" and places it in the String constant pool.
  • The code at reuses the String value "autumn" from the String constant pool. It creates a String object with the value "summer" in the String constant pool (note the difference in the case of letters—Java is case-sensitive and "Summer" is not the same as "summer").
  • The code at creates a new String object with the value "Summer".

The previous code creates a total of five String objects.

Exam Tip

If a String object is created using the keyword new, it always results in the creation of a new String object. String objects created this way are never pooled. When a variable is assigned a String literal using the assignment operator, a new String object is created only if a String object with the same value isn’t found in the String constant pool.

4.1.2. The class String is immutable

The concept that the class String is immutable is an important point to remember. Once created, the contents of an object of the class String can never be modified. The immutability of String objects helps the JVM reuse String objects, reducing memory overhead and increasing performance.

As shown previously in figure 4.4, the JVM creates a pool of String objects that can be referenced by multiple variables across the JVM. The JVM can make this optimization only because String is immutable. String objects can be shared across multiple reference variables without any fear of changes in their values. If the reference variables str1 and str2 refer to the same String object value "Java", str1 need not worry for its lifetime that the value "Java" might be changed through the variable str2.

Let’s take a quick look at how the immutability of the class String is implemented by the authors of this class:

  • The class String stores its values in a private variable of the type char array (char value[]). Arrays are fixed in size and don’t grow once initialized.
  • This value variable is marked as final in the class String. Note that final is a nonaccess modifier, and a final variable can be initialized only once.
  • None of the methods defined in the class String manipulate the individual elements of the array value.

I’ll discuss each of these points in detail in the following sections.

Code from Java API classes

To give you a better understanding of how the classes String, StringBuilder, and ArrayList work, I’ll explain the variables used to store these objects’ values, along with definitions for some of their methods. My purpose is not to overwhelm you but to prepare you. The exam won’t question you on this subject, but these details will help you retain relevant information for the exam and implement similar requirements in code for practical projects.

The source code of the classes defined in the Java API is shipped with the Java Development Kit (JDK). You can access it by unzipping the src.zip archive from your JDK’s installation folder.

The rest of this section discusses how the authors of the Java API have implemented immutability in the class String.

String uses a char array to store its value

Here’s a partial definition of the class String from the Java source code file (String.java) that includes the array used to store the characters of a String value (the relevant code is in bold):

The arrays are fixed in size—they can’t grow once they’re initialized.

Let’s create a variable name of type String and see how it’s stored internally:

String name = "Selvan";

Figure 4.5 shows a UML representation (class diagram on the left and object diagram on the right) of the class String and its object name, with only one relevant variable, value, which is an array of the type char and is used to store the sequence of characters assigned to a String.

Figure 4.5. UML representations of the class String and a String object with String’s instance attribute value

As you can see in figure 4.5, the String value Selvan is stored in an array of type char. In this chapter, I’ll cover arrays in detail, as well as how an array stores its first value at position 0.

Figure 4.6 shows how Selvan is stored as a char array.

Figure 4.6. Mapping characters stored by a String with the positions at which they’re stored

What do you think you’ll get when you request that this String return the character at position 4? If you said a and not v, you got the right answer (as in figure 4.6).

String uses final variable to store its value

The variable value, which is used to store the value of a String object, is marked as final. Review the following code snippet from the class String.java:

The basic characteristic of a final variable is that it can initialize a value only once. By marking the variable value as final, the class String makes sure that it can’t be reassigned a value.

Methods of String don’t modify the char array

Although we can’t reassign a value to a final char array (as mentioned in the previous section), we can reassign its individual characters. Wow—does this mean that the statement “Strings are immutable” isn’t completely true?

No, that statement is still true. The char array used by the class String is marked private, which means that it isn’t accessible outside the class for modification. The class String itself doesn’t modify the value of this variable either.

All the methods defined in the class String, such as substring, concat, toLower-Case, toUpperCase, trim, and so on, which seem to modify the contents of the String object on which they’re called, create and return a new String object rather than modify the existing value. Figure 4.7 illustrates the partial definition of String’s replace method.

Figure 4.7. The partial definition of the method replace from the class String shows that this method creates and returns a new String object rather than modifies the value of the String object on which it’s called.

I reiterate that the previous code from the class String will help you relate the theory to the code and understand how and why a particular concept works. If you understand a particular concept well in terms of how and why it works, you’ll be able to retain that information longer.

Exam Tip

Strings are immutable. Once initialized, a String value can’t be modified. All the String methods that return a modified String value return a new String object with the modified value. The original String value always remains the same.

4.1.3. Methods of the class String

Figure 4.8 categorizes the methods that are on the exam into groups: ones that query the positions of characters, ones that seem to modify String, and others.

Figure 4.8. Categorization of the String methods

Categorizing the methods in this way will help you better understand these methods. For example, the methods charAt(), indexOf(), and substring() query the position of individual characters in a String. The methods substring(), trim(), and replace() seem to be modifying the value of a String.

charAt()

You can use the method charAt(int index) to retrieve a character at a specified index of a String:

Figure 4.9 illustrates the previous string, Paul.

Figure 4.9. The sequence of characters of "Paul" stored by String and the corresponding array index positions

Because the last character is placed at index 3, the following code will throw an exception at runtime:

System.out.println(name.charAt(4));
Note

As a quick introduction, a runtime exception is a programming error determined by the Java Runtime Environment (JRE) during the execution of code. These errors occur because of the inappropriate use of another piece of code (exceptions are covered in detail in chapter 7). The previous code tries to access a nonexistent index position, so it causes an exception.

indexOf()

You can search a String for the occurrence of a char or a String. If the specified char or String is found in the target String, this method returns the first matching position; otherwise, it returns -1:

Figure 4.10 illustrates the previous string ABCAB.

Figure 4.10. The characters "ABCAB" stored by String

By default, the indexOf() method starts its search from the first char of the target String. If you wish, you can also set the starting position, as in the following example:

substring()

The substring() method is shipped in two flavors. The first returns a substring of a String from the position you specify to the end of the String, as in the following example:

Figure 4.11 illustrates the previous example.

Figure 4.11. The String "Oracle"

You can also specify the end position with this method:

Figure 4.12 illustrates the String value "Oracle", including both a start point and an end point for the method substring.

Figure 4.12. How the method substring looks for the specified characters from the start until the end position

An interesting point is that the substring method doesn’t include the character at the end position. In the previous example, result is assigned the value ac (characters at positions 2 and 3), not the value acl (characters at positions 2, 3, and 4). Here’s a simple way to remember this rule:

Length of String returned by substring() = end - start

Exam Tip

The substring method doesn’t include the character at the end position in its return value.

trim()

The trim() method returns a new String by removing all the leading and trailing white space in a String. White spaces are blanks (new lines, spaces, or tabs).

Let’s define and print a String with leading and trailing white space. (The colons printed before and after the String determine the start and end of the String.)

Here’s another example that trims the leading and trailing white space:

Note that this method doesn’t remove the space within a String.

replace()

This method will return a new String by replacing all the occurrences of a char with another char. Instead of specifying a char to be replaced by another char, you can also specify a sequence of characters—a String to be replaced by another String:

Notice the type of the method parameters passed on this method: either char or String. You can’t mix these parameter types, as the following code shows:

Again, notice that this method doesn’t—or can’t—change the value of the variable letters. Examine the following line of code and its output:

length()

You can use the length() method to retrieve the length of a String. Here’s an example showing its use:

Exam Tip

The length of a String is one number greater than the position that stores its last character. The length of String "Shreya" is 6, but its last character, a, is stored at position 5 because the positions start at 0, not 1.

startsWith() and endsWith()

The method startsWith() determines whether a String starts with a specified prefix, specified as a String. You can also specify whether you wish to search from the start of a String or from a particular position. This method returns true if a match is found and false otherwise:

The method endsWith() tests whether a String ends with a particular suffix. It returns true for a matching value and false otherwise:

Method chaining

It’s common practice to use multiple String methods in a single line of code, as follows:

The methods are evaluated from left to right. The first method to execute in this example is replace, not concat.

Method chaining is one of the favorite topics of the exam authors. You’re sure to encounter a question on method chaining in the OCA Java SE 8 Programmer I exam.

Exam Tip

When chained, the methods are evaluated from left to right.

Note that there’s a difference between calling a chain of methods on a String object versus doing the same and then reassigning the return value to the same variable:

Because String objects are immutable, their values won’t change if you execute methods on them. You can, of course, reassign a value to a reference variable of type String. Watch out for related questions in the exam.

Although the next Twist in the Tale exercise may seem simple, with only two lines of code, appearances can be deceptive (answers in the appendix).

Twist in the Tale 4.1

Let’s modify some of the code used in the previous section. Execute this code on your system. Which answer correctly shows its output?

String letters = "ABCAB";
System.out.println(letters.substring(0, 2).startsWith('A'));

  1. true
  2. false
  3. AB
  4. ABC
  5. Compilation error

4.1.4. String objects and operators

Of all the operators that are on this exam, you can use just a handful with the String objects:

  • Concatenation: + and +=
  • Equality: == and !=

In this section, we’ll cover the concatenation operators. We’ll cover the equality operators in the next section (4.1.5).

Concatenation operators (+ and +=) have a special meaning for Strings. The Java language has additional functionality defined for these operators for String. You can use the operators + and += to concatenate two String values. Behind the scenes, string concatenation is implemented by using the StringBuilder (covered in the next section) or StringBuffer (similar to StringBuilder) classes.

But remember that a String is immutable. You can’t modify the value of any existing object of String. The + operator enables you to create a new object of the class String with a value equal to the concatenated values of multiple Strings. Examine the following code:

Here’s another example:

Why do you think the value of the variable anotherStr is 22OCJA and not 1012OCJA? The + operator can be used with the primitive values, and the expression num + val + aStr is evaluated from left to right. Here’s the sequence of steps executed by Java to evaluate the expression:

  • Add operands num and val to get 22.
  • Concatenate 22 with OCJA to get 22OCJA.

If you wish to treat the numbers stored in variables num and val as String values, modify the expression as follows:

A practical tip on String concatenation

During my preparation for my Java Programmer certification, I learned how the output changes in String concatenation when the order of values being concatenated is changed. At work, it helped me to quickly debug a Java application that was logging incorrect values to a log file. It didn’t take me long to discover that the offending line of code was logToFile("Shipped:" + numReceived() + inTransit());. The methods were returning correct values individually, but the return values of these methods were not being added. They were being concatenated as String values, resulting in the unexpected output.

One solution is to enclose the int addition within parentheses, as in logToFile("Shipped:"+ (numReceived() + inTransit()));. This code will log the text "Shipped" with the sum of the numeric values returned by the methods num-Received() and inTransit().

When you use += to concatenate String values, ensure that the variable you’re using has been initialized (and doesn’t contain null). Look at the following code:

4.1.5. Determining equality of Strings

The correct way to compare two String values for equality is to use the equals method defined in the String class. This method returns a true value if the object being compared to it isn’t null, is a String object, and represents the same sequence of characters as the object to which it’s being compared.

equals method

The following listing shows the method definitions of the equals method defined in class String in the Java API.

Listing 4.1. Method definition of the equals method from the class String

In listing 4.1, the equals method accepts a method parameter of type Object and returns a boolean value. Let’s walk through the equals method defined by the class String:

  • compares the object reference variables. If the reference variables are the same, they refer to the same object.
  • compares the type of the method parameter to this object. If the method parameter passed to this method is not of type String, returns false.
  • checks whether the lengths of the String values being compared are equal.
  • compares the individual characters of the String values. It returns false if a mismatch is found at any position. If no mismatch is found, returns true.
Comparing reference variables to instance values

Examine the following code:

The operator == compares the reference variables, that is, whether the variables refer to the same object. Hence, var1 == var2 in the previous code prints false. Now examine the following code:

Even though comparing var3 and var4 using the operator == prints true, you should never use this operator for comparing String values. The variables var3 and var4 refer to the same String object created and shared in the pool of String objects. (We discussed the pool of String objects in section 4.1.1 earlier in this chapter.) The == operator won’t always return the value true, even if the two objects store the same String values.

Exam Tip

The operator == compares whether the reference variables refer to the same objects, and the method equals compares the String values for equality. Always use the equals method to compare two Strings for equality. Never use the == operator for this purpose.

You can use the operator != to compare the inequality of objects referred to by String variables. It’s the inverse of the operator ==. Let’s compare the usage of the operator != with the operator == and the method equals():

The following example uses the operators != and == and the method equals to compare String variables that refer to the same object in the String constant pool:

As you can see, in both of the previous examples the operator != returns the inverse of the value returned by the operator ==.

Equality of values returned by String methods

Do you think the String values returned by methods are stored in the String pool? Will they return true when their variable references are compared using the == operator? Let’s find out:

In the preceding code, the call to lang1.substring() and lang2.subtring() will return "Ja". But these string values aren’t stored in the String pool. This is because these substrings are created using the new operator in String’s method substring (and other String methods). This is confirmed by comparing their reference variables using the == operator, which returns false.

Exam Tip

Watch out for the exam questions that test you on using the == operator with String values returned by methods of the class String. Because these values are created using the new operator, they aren’t placed in the String pool.

Because Strings are immutable, we also need a mutable sequence of characters that can be manipulated. Let’s work with the other type of string on the OCA Java SE 8 Programmer I exam: StringBuilder.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.103.96