Chapter 6
In This Chapter
Using basic looping
Counting as you loop
Repeating relentlessly (until the user gives you a clear answer)
In 1966, the company that brings you Head & Shoulders shampoo made history. On the back of the bottle, the directions for using the shampoo read, “LATHER-RINSE-REPEAT.” Never before had a complete set of directions (for doing anything, let alone shampooing your hair) been summarized so succinctly. People in the direction-writing business hailed this as a monumental achievement. Directions like these stood in stark contrast to others of the time. (For instance, the first sentence on a can of bug spray read, “Turn this can so that it points away from your face.” Duh!)
Aside from their brevity, the thing that made the Head & Shoulders directions so cool was that, with three simple words, it managed to capture a notion that’s at the heart of all instruction-giving — the notion of repetition. That last word, REPEAT, took an otherwise bland instructional drone and turned it into a sophisticated recipe for action.
The fundamental idea is that when you’re following directions, you don’t just follow one instruction after another. Instead, you take turns in the road. You make decisions (“If HAIR IS DRY, then USE CONDITIONER,”) and you go into loops (“LATHER-RINSE, and then LATHER-RINSE again.”). In computer programming, you use decision making and looping all the time. This chapter explores looping in Java.
Here’s a guessing game for you. The computer generates a random number from 1 to 10. The computer asks you to guess the number. If you guess incorrectly, the game continues. As soon as you guess correctly, the game is over. Listing 6-1 shows the program to play the game, and Figure 6-1 shows a round of play.
Listing 6-1: A Repeating Guessing Game
import static java.lang.System.out;
import java.util.Scanner;
import java.util.Random;
public class GuessAgain {
public static void main(String args[]) {
Scanner keyboard = new Scanner(System.in);
int numGuesses = 0;
int randomNumber = new Random().nextInt(10) + 1;
out.println(" ************ ");
out.println("Welcome to the Guessing Game");
out.println(" ************ ");
out.println();
out.print("Enter an int from 1 to 10: ");
int inputNumber = keyboard.nextInt();
numGuesses++;
while (inputNumber != randomNumber) {
out.println();
out.println("Try again...");
out.print("Enter an int from 1 to 10: ");
inputNumber = keyboard.nextInt();
numGuesses++;
}
out.print("You win after ");
out.println(numGuesses + " guesses.");
keyboard.close();
}
}
In Figure 6-1, the user makes four guesses. Each time around, the computer checks to see whether the guess is correct. An incorrect guess generates a request to try again. For a correct guess, the user gets a rousing You win
, along with a tally of the number of guesses he or she made. The computer repeats several statements, checking each time through to see whether the user’s guess is the same as a certain randomly generated number. Each time the user makes a guess, the computer adds 1 to its tally of guesses. When the user makes the correct guess, the computer displays that tally. Figure 6-2 illustrates the flow of action.
When you look over Listing 6-1, you see the code that does all this work. At the core of the code is a thing called a while statement (also known as a while loop). Rephrased in English, the while
statement says:
while the inputNumber is not equal to the randomNumber
keep doing all the stuff in curly braces: {
}
The stuff in curly braces (the stuff that repeats) is the code that prints Try again
and Enter an int...
, gets a value from the keyboard, and adds 1 to the count of the user’s guesses.
The statements in curly braces are repeated as long as inputNumber != randomNumber
is true. Each repetition of the statements in the loop is called an iteration of the loop. In Figure 6-1, the loop undergoes three iterations. (If you don’t believe that Figure 6-1 has exactly three iterations, count the number of Try again
printings in the program’s output. A Try again
appears for each incorrect guess.)
When, at long last, the user enters the correct guess, the computer goes back to the top of the while
statement, checks the condition in parentheses, and finds itself in double double-negative land. The not equal (!=
) relationship between inputNumber
and randomNumber
no longer holds. In other words, the while
statement’s condition, inputNumber != randomNumber
, is false. Because the while
statement’s condition is false, the computer jumps past the while
loop and goes on to the statements just below the while
loop. In these two statements, the computer prints You win after 4 guesses.
“Write ‘I will not talk in class’ on the blackboard 100 times.”
What your teacher really meant was,
Set the count to 0.
As long as the count is less than 100,
Write 'I will not talk in class' on the blackboard,
Add 1 to the count.
Fortunately, you didn’t know about loops and counters at the time. If you pointed out all this stuff to your teacher, you’d have gotten into a lot more trouble than you were already in.
One way or another, life is filled with examples of counting loops. And computer programming mirrors life — or is it the other way around? When you tell a computer what to do, you’re often telling the computer to print three lines, process ten accounts, dial a million phone numbers, or whatever. Because counting loops is so common in programming, the people who create programming languages have developed statements just for loops of this kind. In Java, the statement that repeats something a certain number of times is called a for statement. Listings 6-2 and 6-3 illustrate the use of the for
statement. Listing 6-2 has a rock-bottom simple example, and Listing 6-3 has a more exotic example. Take your pick.
Listing 6-2: The World’s Most Boring for Loop
import static java.lang.System.out;
public class Yawn {
public static void main(String args[]) {
for (int count = 1; count <= 10; count++) {
out.print("The value of count is ");
out.print(count);
out.println(".");
}
out.println("Done!");
}
}
Figure 6-3 shows you what you get when you run the program of Listing 6-2. (You get exactly what you deserve.) The for
statement in Listing 6-2 starts by setting the count
variable to 1. Then the statement tests to make sure that count
is less than or equal to 10 (which it certainly is). Then the for
statement dives ahead and executes the printing statements between the curly braces. (At this early stage of the game, the computer prints The value of count is 1.
) Finally, the for
statement does that last thing inside its parentheses — it adds 1 to the value of count
.
With count
now equal to 2, the for
statement checks again to make sure that count
is less than or equal to 10. (Yes, 2 is smaller than 10.) Because the test turns out okay, the for
statement marches back into the curly braced statements and prints The value of count is 2
on the screen. Finally, the for
statement does that last thing inside its parentheses — it adds 1 to the value of count
, increasing the value of count
to 3
.
And so on. This whole thing repeats until, after 10 iterations, the value of count
finally reaches 11. When this happens, the check for count
being less than or equal to 10 fails, and the loop’s execution ends. The computer jumps to whatever statement comes immediately after the for
statement. In Listing 6-2, the computer prints Done!
Figure 6-4 illustrates the whole process.
After the word for, you always put three things in parentheses. The first of these three things is called an initialization, the second is an expression, and the third thing is called an update.
for ( initialization ; expression ; update )
Each of the three items in parentheses plays its own distinct role:
for
statement.If it helps, think of the loop as if its text is shifted all around:
int count = 1
for count <= 10 {
out.print("The value of count is ");
out.print(count);
out.println(".");
count++
}
You can’t write a real for
statement this way. Even so, this is the order in which the parts of the statement are executed.
Listing 6-2 is very nice, but the program in that listing doesn’t do anything interesting. For a more eye-catching example, see Listing 6-3. In Listing 6-3, I make good on a promise I made in Chapter 5. The program in Listing 6-3 prints all the lyrics of the hit single, “Al’s All Wet.” (You can find the lyrics in Chapter 5.)
Listing 6-3: The Unabridged “Al’s All Wet” Song
import static java.lang.System.out;
public class AlsAllWet {
public static void main(String args[]) {
for (int verse = 1; verse <= 3; verse++) {
out.print("Al's all wet. ");
out.println("Oh, why is Al all wet? Oh,");
out.print("Al's all wet 'cause ");
out.println("he's standing in the rain.");
out.println("Why is Al out in the rain?");
switch (verse) {
case 1:
out.println("That's because he has no brain.");
break;
case 2:
out.println("That's because he is a pain.");
break;
case 3:
out.println("'Cause this is the last refrain.");
break;
}
switch (verse) {
case 3:
out.println("Last refrain, last refrain,");
case 2:
out.println("He's a pain, he's a pain,");
case 1:
out.println("Has no brain, has no brain,");
}
out.println("In the rain, in the rain.");
out.println("Ohhhhhhhh...");
out.println();
}
out.print("Al's all wet. ");
out.println("Oh, why is Al all wet? Oh,");
out.print("Al's all wet 'cause ");
out.println("he's standing in the rain.");
}
}
Listing 6-3 is nice because it combines many of the ideas from Chapters 5 and 6. In Listing 6-3, two switch
statements are nested inside a for
loop. One of the switch
statements uses break
statements; the other switch
statement uses fall-through. As the value of the for
loop’s counter variable (verse
) goes from 1
to 2
and then to 3
, all the cases in the switch
statements are executed. When the program is near the end of its run and execution has dropped out of the for
loop, the program’s last four statements print the song’s final verse.
“Fools rush in where angels fear to tread.”
–Alexander Pope
Today, I want to be young and foolish (or, at the very least, foolish). Look back at Figure 6-2 and notice how Java’s while
loop works. When execution enters a while
loop, the computer checks to make sure that the loop’s condition is true. If the condition isn’t true, the statements inside the loop are never executed — not even once. In fact, you can easily cook up a while
loop whose statements are never executed (although I can’t think of a reason why you would ever want to do it).
int twoPlusTwo = 2 + 2;
while (twoPlusTwo == 5) {
out.println("Are you kidding?");
out.println("2 + 2 doesn't equal 5");
out.print("Everyone knows that");
out.println(" 2 + 2 equals 3");
}
In spite of this silly twoPlusTwo
example, the while
statement turns out to be the most versatile of Java’s looping constructs. In particular, the while
loop is good for situations in which you must look before you leap. For example, “While money is in my account, write a mortgage check every month.” When you first encounter this statement, if your account has a zero balance, you don’t want to write a mortgage check — not even one check.
But at times (not many), you want to leap before you look. Take, for instance, the situation in which you’re asking the user for a response. Maybe the user’s response makes sense, but maybe it doesn’t. If it doesn’t, you want to ask again. Maybe the user’s finger slipped, or perhaps the user didn’t understand the question.
Figure 6-5 shows some runs of a program to delete a file. Before deleting the file, the program asks the user whether making the deletion is okay. If the user answers y or n, the program proceeds according to the user’s wishes. But if the user enters any other character (any digit, uppercase letter, punctuation symbol, or whatever), the program asks the user for another response.
To write this program, you need a loop — a loop that repeatedly asks the user whether the file should be deleted. The loop keeps asking until the user gives a meaningful response. Now, the thing to notice is that the loop doesn’t need to check anything before asking the user the first time. Indeed, before the user gives the first response, the loop has nothing to check. The loop doesn’t start with “as long as such-and-such is true, then get a response from the user.” Instead, the loop just leaps ahead, gets a response from the user, and then checks the response to see whether it makes sense.
That’s why the program in Listing 6-4 has a do loop (also known as a do … while loop). With a do
loop, the program jumps right in, takes action, and then checks a condition to see whether the result of the action makes sense. If the result makes sense, execution of the loop is done. If not, the program goes back to the top of the loop for another go-around.
Listing 6-4: To Delete or Not to Delete
import java.io.File;
import static java.lang.System.out;
import java.util.Scanner;
public class DeleteEvidence {
public static void main(String args[]) {
File evidence = new File("cookedBooks.txt");
Scanner keyboard = new Scanner(System.in);
char reply;
do {
out.print("Delete evidence? (y/n) ");
reply =
keyboard.findWithinHorizon(".",0).charAt(0);
} while (reply != 'y' && reply != 'n'),
if (reply == 'y') {
out.println("Okay, here goes...");
evidence.delete();
out.println("The evidence has been deleted.");
} else {
out.println("Sorry, buddy. Just asking.");
}
keyboard.close();
}
}
Figure 6-5 shows two runs of the code in Listing 6-4. The program accepts lowercase letters y and n, but not the uppercase letters Y and N. To make the program accept uppercase letters, change the conditions in the code as follows:
do {
out.print("Delete evidence? (y/n) ");
reply = keyboard.findWithinHorizon(".", 0).charAt(0);
} while (reply != 'y' && reply != 'Y' &&
reply != 'n' && reply!='N');
if (reply == 'y' || reply == 'Y') {
Figure 6-6 shows the flow of control in the loop of Listing 6-4. With a do
loop, the situation in the twoPlusTwo
program (shown at the beginning of this section) can never happen. Because the do
loop carries out its first action without testing a condition, every do
loop is guaranteed to perform at least one iteration.
Back in Listing 5-3 from Chapter 5, the user types a word on the keyboard. The keyboard.next
method grabs the word and places the word into a String
variable named password. Everything works nicely because a String
variable can store many characters at once, and the next
method can read many characters at once.
But in Listing 6-4, you’re not interested in reading several characters. You expect the user to type one letter — either y or n. So you don’t create a String
variable to store the user’s response. Instead, you create a char
variable — a variable that stores just one symbol at a time.
The Java API doesn’t have a nextChar
method. So to read something suitable for storage in a char
variable, you have to improvise. In Listing 6-4, the improvisation looks like this:
keyboard.findWithinHorizon(".", 0).charAt(0)
You can use this code exactly as it appears in Listing 6-4 whenever you want to read a single character.
In Listing 6-4, the actual file-handling statements deserve some attention. These statements involve the use of classes, objects, and methods. Many of the meaty details about these things are in other chapters, like Chapters 7 and 9. Even so, I can’t do any harm by touching on some highlights right here.
So, you can find a class in the Java language API named java.io.File. The statement
File evidence = new File("cookedBooks.txt");
creates a new object in the computer’s memory. This object, formed from the java.io.File
class, describes everything that the program needs to know about the disk file cookedBooks.txt
. From this point on in Listing 6-4, the variable evidence
refers to the disk file cookedBooks.txt
.
The evidence
object, being an instance of the java.io.File
class, has a delete
method. (What can I say? It’s in the API documentation.) When you call evidence.delete
, the computer gets rid of the file for you.
Of course, you can't get rid of something that doesn't already exist. When you call the constructor
File evidence = new File("cookedBooks.txt");
Java doesn't check to make sure that you have a file named cookedBooks.txt
. To force Java to do the checking, you have a few options. The simplest is to call the exists
method. When you call evidence.exists()
, the method looks in the folder where Java expects to find cookedBooks.txt
. The call evidence.exists()
returns true
if Java finds cookedBooks.txt
inside that folder. Otherwise, the call evidence.exists()
returns false
. Here's a souped-up version of Listing 6-4, with a call to exists
included in the code:
import java.io.File;
import static java.lang.System.out;
import java.util.Scanner;
public class DeleteEvidence {
public static void main(String args[]) {
File evidence = new File("cookedBooks.txt");
if (evidence.exists()) {
Scanner keyboard = new Scanner(System.in);
char reply;
do {
out.print("Delete evidence? (y/n) ");
reply =
keyboard.findWithinHorizon(".", 0).charAt(0);
} while (reply != 'y' && reply != 'n'),
if (reply == 'y') {
out.println("Okay, here goes...");
evidence.delete();
out.println("The evidence has been deleted.");
} else {
out.println("Sorry, buddy. Just asking.");
}
keyboard.close();
}
}
}
A bunch of statements surrounded by curly braces forms a block. If you declare a variable inside a block, you generally can’t use that variable outside the block. For instance, in Listing 6-4, you get an error message if you make the following change:
do {
out.print("Delete evidence? (y/n) ");
char reply =
keyboard.findWithinHorizon(".", 0).charAt(0);
} while (reply != 'y' && reply != 'n'),
if (reply == 'y')
With the declaration char reply
inside the loop’s curly braces, no use of the name reply
makes sense anywhere outside the braces. When you try to compile this code, you get three error messages — two for the reply
words in while (reply != 'y' && reply != 'n')
and a third for the if
statement’s reply
.
So in Listing 6-4, your hands are tied. The program’s first real use of the reply
variable is inside the loop. But to make that variable available after the loop, you have to declare reply
before the loop. In this situation, you’re best off declaring the reply
variable without initializing the variable. Very interesting!
All versions of Java have the three kinds of loops described in this chapter (while
loops, for
loops, and do . . . while
loops). But newer Java versions (namely, Java 5 and beyond) have yet another kind of loop called an enhanced for loop. For a look at Java's enhanced for
loop, see Chapter 11.
3.133.151.220