Strictly speaking, it isn't quite true that String is the
only class that permits any operators to be applied to its objects:
There are three operators
that can be applied to objects of all classes: ==, !=, and
=. And later we'll see a special object type called
an array that permits the bracket operator.
But the String class is the only normal
class that allows any
other operators to be applied to its instances.
Chapter 8. Strings
Programs must often manipulate text, like words or sentences.
Such text is composed of
Java includes the String class, each instance of which
represents a string of characters.
This class is one of the most heavily used in
Java, and we study it in this
chapter.
8.1. The String class
All Java classes require the use of new to create new
instances of that class — with one exception. That exception is
the String class, which is so useful
that Java designers built special support for it into the language.
To create a String object representing a sequence of characters,
you need only to enclose that sequence inside a pair of double
quotes.
String sentence = "Hello, world.";
In this code fragment, we create a variable named sentence, and
we assign it to refer to the string Hello, world.
Sometimes you may want to include quotation marks inside a string. To do this, you can precede the quotation marks with a backslash.
String quote = "Frobozz said, \"Hello, sailor.\"";
If for some reason you wanted a backslash in a string, then you would precede it with a backslash.
There is another special exception with String objects, too:
For other classes, you cannot apply operators like * or >
to their objects; such operators can be applied only to primitive types
like int and double. But you can apply the +
operator using the String class; in this case, it combines values
into a larger string.
In the below example, we suppose that
name is a String variable that has already been assigned
to reference the user's name.
String greeting = "Hello, " + name + ".";
This fragment creates a new variable greeting. If name
references the string Dave
, greeting will be
assigned to reference the string Hello, Dave.
If name were Dolly
, greeting would
reference Hello, Dolly.
A program can add any type onto a String object, resulting
in another String object. Suppose for example that k is an
int variable holding the value 42.
String s = "k is " + k + ".";
The above fragment would assign s to be the string
k is 42.
That is, it places the two characters
'4' and '2' into the string, since these two digits
constitute the decimal expansion of the value referenced by
k.
Sometimes this usage of + can lead to unusual behavior.
What string do you suppose the following would compute?
String t = "k+1 is " + k+1 + ".";
We would hope that t would reference
k+1 is 43.
But in fact this fragment creates
the string k+1 is 421.
The Java compiler
simply sees the usage of the + operator, and computes it
left-to-right. So the computer first adds k to
k+1 is
,
then it adds 1 onto that, and
finally it adds a period.
(The compiler doesn't pay attention to the spaces.)
8.2. String input and output
The GraphicsProgram class includes several methods that use the
String class. Most accept a String as a parameter that
is then displayed for the user to see.
void print(String message)Displays
messageto the user, leaving the cursor at the character following the last character ofmessage(without advancing to the next line).void println(String message)Displays
messageto the user and advances the cursor to the next line's beginning.double readDouble(String message)Displays
messageto the user, waits for the user to type a number, and then returns the number the user typed.int readInt(String message)Displays
messageto the user, waits for the user to type a integer, and then returns the integer the user typed.String readLine(String message)Displays
messageto the user, waits for the user to type a line of text, and then returns aStringholding the characters typed by the user (omitting the final end-of-line character).
Note that GraphicsWindow also has readInt and
readDouble methods that take no parameters, in addition to the
above. Java allows multiple methods with the same name: When a program
invokes a method for which multiple methods are named identically, the
compiler will count the parameters and identify the parameter types,
and use that to determine the appropriate method. (The compiler will not
allow a class to define two methods with the same number of parameters,
and with the corresponding parameter types all being identical.)
Figure 8.1 contains an example of a program
using these methods. It is an enhanced version of the MovingBall
program of Figure 6.3. In this version, the user
first enters the ball's
initial velocity. This version also informs the user once the ball has
exited the screen.
Figure 8.1: The
CustomMovingBallprogram.1 import acm.program.*;
2 import acm.graphics.*;
3 import java.awt.*;
4
5 public class CustomMovingBall extends GraphicsProgram {
6 public void run() {
7 double xVelocity = readDouble("Horizontal velocity? ");
8 double yVelocity = readDouble("Vertical velocity? ");
9
10 GOval ball = new GOval(25, 25, 50, 50);
11 ball.setFilled(true);
12 ball.setFillColor(new Color(255, 0, 0));
13 add(ball);
14
15 println("Ball starts rolling.");
16 int frames = 0;
17 while(ball.getX() < getWidth() && ball.getX() > -ball.getWidth()
18 && ball.getY() < getHeight() && ball.getY() > -ball.getHeight()) {
19 pause(40);
20 frames++;
21 ball.move(xVelocity, yVelocity);
22 }
23 println("Ball exited window after " + frames + " frames.");
24 }
25 }
Notice how line 23 builds the string to be
printed by adding an int variable's value onto the end of a
string.
When executed, the program displays the following; the user's input is displayed in boldface. This dialogue will take place in a completely separate place from where the graphics are displayed. Exactly where the dialogue takes place depends on your computer's configuration, but the best bet is the window from where you started the program.
Horizontal velocity? 8 Vertical velocity? 6 Ball starts rolling. output pauses while ball rolls across screen Ball exited screen after 78 frames.
8.3. String methods
As a class defined in the Java libraries, the String class
defines several methods that an individual
String object can perform.
int length()Returns the number of characters in this string.
String substring(int begin)Returns a string containing the characters of this string beginning at index
beginand going to this string's end.String substring(int begin, int end)Returns a string containing the characters of this string beginning at index
beginand going up to — but not including — indexend.
It's important to understand that the index of the first character of
the string is 0, the second character's index is 1, and so on.
The final character of a string str is at index
str.length() - 1; the index is not at str.length()
because the counting starts from 0.
Suppose we want to print a particular string in reverse; for example, if
the user types straw,
we want the program to print warts.
The following code segment accomplishes this.
String str = readLine("Type a string to reverse: ");
int toPrint = str.length();
while(toPrint > 0) {
print(str.substring(toPrint - 1, toPrint));
toPrint--;
}
This fragment uses a counter toPrint to track how many
characters are left to print. As long as there are characters are left
(as the while loop indicates), the program will display the
substring consisting
of the toPrintth character, and then decrement toPrint.
Notice that, in invoking
substring method, the program passes toPrint - 1
as the beginning point; we subtract 1 because the characters are
numbered starting at 0. For the ending point, we pass toPrint,
since this is the first index we do not want.
The substring method's behavior of omitting the last
character in the range named is not what you
would expect, and beginners often have trouble with this. The designers
chose this because it tends to simplify the underlying program. For
example, the number of characters fetched by the substring
method is end - begin.
8.4. Equality testing
Suppose we wanted to write a program to repeatedly ask the user for a password until the user types the correct password. Supposing the password is friend, you might be tempted to retrieve the password using the following program fragment.
String password = readLine("Password? ");
while(password != "friend") { // Wrong!
password = readLine("Wrong. Password? ");
}
println("You're in.");
This reads a password from the user. As long as the word the user types isn't friend, the program continues asking for another word.
The idea's good, and the program will compile and run, but when we test
it, it won't work. It will keep saying that we were wrong, even when we
type friend
at the prompt.
The problem is that the test in the while loop to see if two
objects are equal actually tests to
see if the two objects are the same. As it turns out, password
and the string created by enclosing friend
in double-quotations
marks, are two different strings, located at different points in the
computer's memory, even though they happen to contain the same letters.
They're identical, but they're not the same. It's the same principle
that leads me to assert that two identical blue M&M candies laid
side by side
are nonetheless different: Even if they are indistinguishible, they're
not the same piece of candy.
Thus, the while loop's condition will
always turn out to be true: password will never equal
"friend", even if password contains the same letters.
So how can we compare two strings to see if they contain the same
letters? Luckily, Java's String class includes some methods
to help with this dilemma.
boolean equals(String other)Return
trueif this string contains the same sequence of characters asotherdoes. For the purpose of equality testing, lower-case letters are treated as different from their corresponding capital letters. Thus ifsismacintosh
, the invocations.equals("MacIntosh")returnsfalse.boolean equalsIgnoreCase(String other)Return
trueif this string contains the same sequence of characters asotherdoes, treating lower-case letters as identical to their corresponding capital letters.
We can repair our program fragment by using the equals method
to compare the two strings.
while(!password.equals("friend")) { // ok
The equals method will look through the characters of
password and see if they all match up with the corresponding
characters of "friend". If they do, it returns true, and
this while condition (with its exclamation point for
representing not) will have a value of false, so that
the computer will proceed to the first statement following the
while loop. If they don't match, the equals method
returns false, so that the value of the condition is true,
and so the computer will go through another iteration of the loop,
asking the user to try again.
Suppose a user executes the program of Figure 8.2 and
types 5 when prompted. What does the program display?
Figure 8.2: The
Bombprogram.1 import acm.program.*;
2
3 public class Bomb extends GraphicsProgram {
4 public void run() {
5 int num = readInt("Integer? ");
6 String str = "B";
7 while(num > 0) {
8 println("" + num);
9 str += "O";
10 num--;
11 }
12 println(str + "M!");
13 }
14 }
The GLabel class allows a string to appear as a shape
in the window. Write a program that displays a phrase that slowly
scrolls horizontally across the screen before wrapping around. (You
can do this by drawing the phrase twice each animation frame, with the
first string possibly starting outside the window's left edge, and the
second string possibly going off the window's right edge.)
Write a program that reads in a number and prints its square right-justified over 10 columns.
Number? 456
456
To convert the number into a string, you can add it to an empty
string:
gives you the string of digits
corresponding to the "" + kint referenced by k.
Then you
can use the length instance method in the String class to
determine how many spaces you need to print.
