Chapter 5

Controlling Program Flow with Decision-Making Statements

In This Chapter

arrow Writing statements that choose between alternatives

arrow Putting statements inside one another

arrow Choosing among many alternatives

The TV show Dennis the Menace aired on CBS from 1959 to 1963. I remember one episode in which Mr. Wilson was having trouble making an important decision. I think it was something about changing jobs or moving to a new town. Anyway, I can still see that shot of Mr. Wilson sitting in his yard, sipping lemonade, and staring into nowhere for the whole afternoon. Of course, the annoying character Dennis was constantly interrupting Mr. Wilson’s peace and quiet. That’s what made this situation funny.

What impressed me about this episode (the reason why I remember it so clearly even now) was Mr. Wilson’s dogged intent in making the decision. This guy wasn’t going about his everyday business, roaming around the neighborhood, while thoughts about the decision wandered in and out of his mind. He was sitting quietly in his yard, making marks carefully and logically on his mental balance sheet. How many people actually make decisions this way?

At that time, I was still pretty young. I’d never faced the responsibility of having to make a big decision that affected my family and me. But I wondered what such a decision-making process would be like. Would it help to sit there like a stump for hours on end? Would I make my decisions by the careful weighing and tallying of options? Or would I shoot in the dark, take risks, and act on impulse? Only time would tell.

Making Decisions (Java if Statements)

When you’re writing computer programs, you’re constantly hitting forks in roads. Did the user correctly type his or her password? If yes, let the user work; if no, kick the bum out. So the Java programming language needs a way of making a program branch in one of two directions. Fortunately, the language has a way. It’s called an if statement.

Guess the number

Listing 5-1 illustrates the use of an if statement. Two runs of the program in Listing 5-1 are shown in Figure 5-1.

Listing 5-1: A Guessing Game

import static java.lang.System.out;

import java.util.Scanner;

import java.util.Random;

class GuessingGame {

public static void main(String args[]) {

Scanner keyboard = new Scanner(System.in);

out.print(“Enter an int from 1 to 10: “);

int inputNumber = keyboard.nextInt();

int randomNumber = new Random().nextInt(10) + 1;

if (inputNumber == randomNumber) {

out.println(“**********”);

out.println(“*You win.*”);

out.println(“**********”);

} else {

out.println(“You lose.”);

out.print(“The random number was “);

out.println(randomNumber + “.”);

}

out.println(“Thank you for playing.”);

}

}

Figure 5-1: Two runs of the guessing game.

9781118128329 fg0501.tif

The program in Listing 5-1 plays a guessing game with the user. The program gets a number (a guess) from the user and then generates a random number between 1 and 10. If the number that the user entered is the same as the random number, the user wins. Otherwise, the user loses, and the program tells the user what the random number was.

She controlled keystrokes from the keyboard

Taken together, the lines

import java.util.Scanner;

Scanner keyboard = new Scanner(System.in);

int inputNumber = keyboard.nextInt();

in Listing 5-1 get whatever number the user types on the computer’s keyboard. The last of the three lines puts this number into a variable named inputNumber. If these lines look complicated, don’t worry. You can copy these lines almost word for word whenever you want to read from the keyboard. Include the first two lines (the import and Scanner lines) just once in your program. Later in your program, wherever the user types an int value, include a line with a call to nextInt (as in the last of the preceding three lines of code).

Of all the names in these three lines of code, the only two names that I coined myself are inputNumber and keyboard. All the other names are part of Java. So, if I want to be creative, I can write the lines this way:

import java.util.Scanner;

Scanner readingThingie = new Scanner(System.in);

int valueTypedIn = readingThingie.nextInt();

I can also beef up my program’s import declarations, as I do in Listings 5-2 and 5-3. Other than that, I have very little leeway.

As you read on in this book, you’ll start recognizing the patterns behind these three lines of code, so I don’t clutter up this section with all the details. For now, you can just copy these three lines and keep the following in mind:

check.png When you import java.util.Scanner, you don’t use the word static.

But importing Scanner is different from importing System.out. When you import java.lang.System.out, you use the word static. (See Listing 5-1.) The difference creeps into the code because Scanner is the name of a class, and System.out isn’t the name of a class.

cross-reference.eps For a quick look at the use of the word static in import declarations, see one of the sidebars in Chapter 4. For a more complete story about the word, see Chapter 10.

check.png The name System.in stands for the keyboard.

To get characters from some place other than the keyboard, you can type something other than System.in inside the parentheses.

cross-reference.eps What else can you put inside the parentheses? For some ideas, see Chapter 8.

remember.eps In Listing 5-1, I make the arbitrary decision to give one of my variables the name keyboard. The name keyboard reminds you, the reader, that this variable refers to a bunch of plastic buttons in front of your computer. Naming something keyboard doesn’t tell Java anything about plastic buttons or about user input. On the other hand, the name System.in always tells Java about those plastic buttons. The code Scanner keyboard = new Scanner(System.in) in Listing 5-1 connects the name keyboard with the plastic buttons that we all know and love.

check.png When you expect the user to type an int value (a whole number of some kind), use nextInt().

If you expect the user to type a double value (a number containing a decimal point), use nextDouble(). If you expect the user to type true or false, use nextBoolean(). If you expect the user to type a word like Barry, Java, or Hello, use next().

cross-reference.eps For an example in which the user types a word, see Listing 5-3. For an example in which the user types a single character, see Listing 6-4 in Chapter 6. For an example in which a program reads an entire line of text (all in one big gulp), see Chapter 8.

check.png You can get several values from the keyboard, one after another.

To do this, use the keyboard.nextInt() code several times.

cross-reference.eps To see a program that reads more than one value from the keyboard, go to Listing 5-4.

Creating randomness

Achieving real randomness is surprisingly difficult. Mathematician Persi Diaconis says that if you flip a coin several times, always starting with the head side up, you’re likely to toss heads more often than tails. If you toss several more times, always starting with the tail side up, you’re likely to toss tails more often than heads. In other words, coin tossing isn’t really fair.*

Computers aren’t much better than coins and human thumbs. A computer mimics the generation of random sequences but, in the end, the computer just does what it’s told and does all this in a purely deterministic fashion. So in Listing 5-1, when the computer executes

import java.util.Random;

int randomNumber = new Random().nextInt(10) + 1;

the computer appears to give us a randomly generated number — a whole number between 1 and 10. But it’s all a fake. The computer just follows instructions. It’s not really random, but without bending a computer over backwards, it’s the best that anyone can do.

Once again, I ask you to take this code on blind faith. Don’t worry about what new Random().nextInt means until you have more experience with Java. Just copy this code into your own programs and have fun with it. And if the numbers from 1 to 10 aren’t in your flight plans, don’t fret. To roll an imaginary die, write the statement

int rollEmBaby = new Random().nextInt(6) + 1;

With the execution of this statement, the variable rollEmBaby gets a value from 1 to 6.

The if statement

At the core of Listing 5-1 is a Java if statement. This if statement represents a fork in the road. (See Figure 5-2.) The computer follows one of two prongs — the prong that prints You win or the prong that prints You lose. The computer decides which prong to take by testing the truth or falsehood of a condition. In Listing 5-1, the condition being tested is

inputNumber == randomNumber

Does the value of inputNumber equal the value of randomNumber? When the condition is true, the computer does the stuff between the condition and the word else. When the condition turns out to be false, the computer does the stuff after the word else. Either way, the computer goes on to execute the last println call, which displays Thank you for playing.

remember.eps The condition in an if statement must be enclosed in parentheses. However, a line like if (inputNumber == randomNumber) is not a complete statement (just as “If I had a hammer” isn’t a complete sentence). So this line if (inputNumber == randomNumber) shouldn’t end with a semicolon.

Figure 5-2: An if statement is like a fork in the road.

9781118128329 fg0502.eps

technicalstuff.eps Sometimes, when I’m writing about a condition that’s being tested, I slip into using the word expression instead of condition. That’s okay, because every condition is an expression. An expression is something that has a value and, sure enough, every condition has a value. The condition’s value is either true or false. (For revealing information about expressions and values like true and false, see Chapter 4.)

The double equal sign

In Listing 5-1, in the if statement’s condition, notice the use of the double equal sign. Comparing two numbers to see whether they’re the same isn’t the same as setting something equal to something else. That’s why the symbol to compare for equality isn’t the same as the symbol that’s used in an assignment or an initialization. In an if statement’s condition, you can’t replace the double equal sign with a single equal sign. If you do, your program just won’t work. (You almost always get an error message when you try to compile your code.)

On the other hand, if you never make the mistake of using a single equal sign in a condition, you’re not normal. Not long ago, while I was teaching an introductory Java course, I promised that I’d swallow my laser pointer if no one made the single equal sign mistake during any of the lab sessions. This wasn’t an idle promise. I knew I’d never have to keep it. As it turned out, even if I had ignored the first ten times anybody made the single equal sign mistake during those lab sessions, I would still be laser-pointer free. Everybody mistakenly uses the single equal sign several times in his or her programming career. The trick is not to avoid making the mistake; the trick is to catch the mistake whenever you make it.

Brace yourself

The if statement in Listing 5-1 has two halves — a top half and a bottom half. I have names for these two parts of an if statement. I call them the if part (the top half) and the else part (the bottom half).

The if part in Listing 5-1 seems to have more than one statement in it. I make this happen by enclosing the three statements of the if part in a pair of curly braces. When I do this, I form a block. A block is a bunch of statements scrunched together by a pair of curly braces.

With this block, three calls to println are tucked away safely inside the if part. With the curly braces, the rows of asterisks and the words You win display only when the user’s guess is correct.

This business with blocks and curly braces applies to the else part as well. In Listing 5-1, whenever inputNumber doesn’t equal randomNumber, the computer executes three print/println calls. To convince the computer that all three of these calls are inside the else clause, I put these calls into a block. That is, I enclose these three calls in a pair of curly braces.

technicalstuff.eps Strictly speaking, Listing 5-1 has only one statement between the if and the else statements and only one statement after the else statement. The trick is that when you place a bunch of statements inside curly braces, you get a block; and a block behaves, in all respects, like a single statement. In fact, the official Java documentation lists blocks as one of the many kinds of statements. So, in Listing 5-1, the block that prints You win and asterisks is a single statement that has, within it, three smaller statements.

Indenting if statements in your code

Notice how, in Listing 5-1, the print and println calls inside the if statement are indented. (This includes both the You win and You lose statements. The print and println calls that come after the word else are still part of the if statement.) Strictly speaking, you don’t have to indent the statements that are inside an if statement. For all the compiler cares, you can write your whole program on a single line or place all your statements in an artful, misshapen zigzag. The problem is that neither you nor anyone else can make sense of your code if you don’t indent your statements in some logical fashion. In Listing 5-1, the indenting of the print and println statements helps your eye (and brain) see quickly that these statements are subordinate to the overall if/else flow.

In a small program, unindented or poorly indented code is barely tolerable. But in a complicated program, indentation that doesn’t follow a neat, logical pattern is a big, ugly nightmare.

ontheweb.eps Many Java IDEs have tools to indent your code automatically. In fact, code indentation is one of my favorite IDE features. So don’t walk — run — to a computer, and visit this book’s website for more information on what Java IDEs can offer.

When you write if statements, you may be tempted to chuck all the rules about curly braces out the window and just rely on indentation. Unfortunately, this seldom works. If you indent three statements after the word else and forget to enclose those statements in curly braces, the computer thinks that the else part includes only the first of the three statements. What’s worse, the indentation misleads you into believing that the else part includes all three statements. This makes it more difficult for you to figure out why your code isn’t behaving the way you think it should behave. So watch those braces!

Elseless in Ifrica

Okay, so the title of this section is contrived. Big deal! The idea is that you can create an if statement without the else part. Take, for instance, the code in Listing 5-1. Maybe you’d rather not rub it in whenever the user loses the game. The modified code in Listing 5-2 shows you how to do this (and Figure 5-3 shows you the result).

Listing 5-2: A Kinder, Gentler Guessing Game

import static java.lang.System.in;

import static java.lang.System.out;

import java.util.Scanner;

import java.util.Random;

class DontTellThemTheyLost {

public static void main(String args[]) {

Scanner keyboard = new Scanner(in);

out.print(“Enter an int from 1 to 10: “);

int inputNumber = keyboard.nextInt();

int randomNumber = new Random().nextInt(10) + 1;

if (inputNumber == randomNumber) {

out.println(“*You win.*”);

}

out.println(“That was a very good guess :-)”);

out.print(“The random number was “);

out.println(randomNumber + “.”);

out.println(“Thank you for playing.”);

}

}

Figure 5-3: Two runs of the game in Listing 5-2.

9781118128329 fg0503.tif

The if statement in Listing 5-2 has no else part. When inputNumber is the same as randomNumber, the computer prints You win. When inputNumber is different from randomNumber, the computer doesn’t print You win.

Listing 5-2 illustrates another new idea. With an import declaration for System.in, I can reduce new Scanner(System.in) to the shorter new Scanner(in). Adding this import declaration is hardly worth the effort. In fact, I do more typing with the import declaration than without it. Nevertheless, the code in Listing 5-2 demonstrates that it’s possible to import System.in.

Forming Conditions with Comparisons and Logical Operators

The Java programming language has plenty of little squiggles and doodads for your various condition-forming needs. This section tells you all about them.

Comparing numbers; comparing characters

Table 5-1 shows you the operators that you can use to compare one thing with another.

Table 5-1 Comparison Operators

Operator Symbol

Meaning

Example

==

is equal to

numberOfCows == 5

!=

is not equal to

buttonClicked != panicButton

<

is less than

numberOfCows < 5

>

is greater than

myInitial > ‘B’

<=

is less than or equal to

numberOfCows <= 5

>=

is greater than or equal to

myInitial >= ‘B’

You can use all Java’s comparison operators to compare numbers and characters. When you compare numbers, things go pretty much the way you think they should go. But when you compare characters, things are a little strange. Comparing uppercase letters with one another is no problem. Because the letter B comes alphabetically before H, the condition ‘B’ < ‘H’ is true. Comparing lowercase letters with one another is also okay. What’s strange is that when you compare an uppercase letter with a lowercase letter, the uppercase letter is always smaller. So, even though ‘Z’ < ‘A’ is false, ‘Z’ < ‘a’ is true.

technicalstuff.eps Under the hood, the letters A through Z are stored with numeric codes 65 through 90. The letters a through z are stored with codes 97 through 122. That’s why each uppercase letter is smaller than each lowercase letter.

warning_bomb.eps Be careful when you compare two numbers for equality (with ==) or inequality (with !=). After doing some calculations and obtaining two double values or two float values, the values that you have are seldom dead-on equal to one another. (The problem comes from those pesky digits beyond the decimal point.) For instance, the Fahrenheit equivalent of 21 degrees Celsius is 69.8, and when you calculate 9.0 / 5 * 21 + 32 by hand, you get 69.8. But the condition 9.0 / 5 * 21 + 32 == 69.8 turns out to be false. That’s because, when the computer calculates 9.0 / 5 * 21 + 32, it gets 69.80000000000001, not 69.8.

Comparing objects

When you start working with objects, you find that you can use == and != to compare objects with one another. For instance, a button that you see on the computer screen is an object. You can ask whether the thing that was just mouse-clicked is a particular button on your screen. You do this with Java’s equality operator.

if (e.getSource() == bCopy) {

clipboard.setText(which.getText());

cross-reference.eps To find out more about responding to button clicks, read Chapter 16.

The big gotcha with Java’s comparison scheme comes when you compare two strings. (For a word or two about Java’s String type, see the section about reference types in Chapter 4.) When you compare two strings with one another, you don’t want to use the double equal sign. Using the double equal sign would ask, “Is this string stored in exactly the same place in memory as that other string?” Usually, that’s not what you want to ask. Instead, you usually want to ask, “Does this string have the same characters in it as that other string?” To ask the second question (the more appropriate question) Java’s String type has a method named equals. (Like everything else in the known universe, this equals method is defined in the Java API, short for Application Programming Interface.) The equals method compares two strings to see whether they have the same characters in them. For an example using Java’s equals method, see Listing 5-3. (Figure 5-4 shows a run of the program in Listing 5-3.)

Listing 5-3: Checking a Password

import static java.lang.System.*;

import java.util.Scanner;

class CheckPassword {

public static void main(String args[]) {

out.print(“What’s the password? “);

Scanner keyboard = new Scanner(in);

String password = keyboard.next();

out.println(“You typed >>” + password + “<<”);

out.println();

if (password == “swordfish”) {

out.println(“The word you typed is stored”);

out.println(“in the same place as the real”);

out.println(“password. You must be a”);

out.println(“hacker.”);

} else {

out.println(“The word you typed is not”);

out.println(“stored in the same place as”);

out.println(“the real password, but that’s”);

out.println(“no big deal.”);

}

out.println();

if (password.equals(“swordfish”)) {

out.println(“The word you typed has the”);

out.println(“same characters as the real”);

out.println(“password. You can use our”);

out.println(“precious system.”);

} else {

out.println(“The word you typed doesn’t”);

out.println(“have the same characters as”);

out.println(“the real password. You can’t”);

out.println(“use our precious system.”);

}

}

}

In Listing 5-3, the call keyboard.next() grabs whatever word the user types on the computer keyboard. The code shoves this word into the variable named password. Then the program’s if statements use two different techniques to compare password with “swordfish”.

Figure 5-4: The result of using == and using Java’s equals method.

9781118128329 fg0504.tif

The more appropriate of the two techniques uses Java’s equals method. The equals method looks funny because when you call it, you put a dot after one string and put the other string in parentheses. But that’s the way you have to do it.

In calling Java’s equals method, it doesn’t matter which string gets the dot and which gets the parentheses. For instance, in Listing 5-3, you could have written

if (“swordfish”.equals(password))

The method would work just as well.

technicalstuff.eps A call to Java’s equals method looks imbalanced, but it’s not. There’s a reason behind the apparent imbalance between the dot and the parentheses. The idea is that you have two objects: the password object and the “swordfish” object. Each of these two objects is of type String. (However, password is a variable of type String, and “swordfish” is a String literal.) When you write password.equals(“swordfish”), you’re calling an equals method that belongs to the password object. When you call that method, you’re feeding “swordfish” to the method as the method’s parameter (pun intended).

cross-reference.eps You can read more about methods belonging to objects in Chapter 7.

When comparing strings with one another, use the equals method — not the double equal sign.

Importing everything in one fell swoop

The first line of Listing 5-3 illustrates a lazy way of importing both System.out and System.in. To import everything that System has to offer, you use the asterisk wildcard character (*). In fact, importing java.lang.System.* is like having about 30 separate import declarations, including System.in, System.out, System.err, System.nanoTime, and many other System things.

The use of an asterisk in an import declaration is generally considered bad programming practice, so I don’t do it often in this book’s examples. But for larger programs — programs that use dozens of names from the Java API — the lazy asterisk trick is handy.

technicalstuff.eps You can’t toss an asterisk anywhere you want inside an import declaration. For example, you can’t import everything starting with java by writing import java.*. You can substitute an asterisk only for the name of a class or for the name of something static that’s tucked away inside a class. For more information about asterisks in import declarations, see Chapter 9. For information about static things, see Chapter 10.

Java’s logical operators

Mr. Spock would be pleased. Java has all the operators that you need for mixing and matching logical tests. The operators are shown in Table 5-2.

Table 5-2 Logical Operators

Operator Symbol

Meaning

Example

&&

and

5 < x && x < 10

||

or

x < 5 || 10 < x

!

not

!password.equals(“swordfish”)

You can use these operators to form all kinds of elaborate conditions. Listing 5-4 has an example.

Listing 5-4: Checking Username and Password

import javax.swing.JOptionPane;

class Authenticator {

public static void main(String args[]) {

String username =

JOptionPane.showInputDialog(“Username:”);

String password =

JOptionPane.showInputDialog(“Password:”);

if (

username != null &&

password != null &&

(

(username.equals(“bburd”) &&

password.equals(“swordfish”)) ||

(username.equals(“hritter”) &&

password.equals(“preakston”))

)

)

{

JOptionPane.showMessageDialog

(null, “You’re in.”);

} else {

JOptionPane.showMessageDialog

(null, “You’re suspicious.”);

}

}

}

Several runs of the program of Listing 5-4 are shown in Figure 5-5. When the username is bburd and the password is swordfish or when the username is hritter and the password is preakston, the user gets a nice message. Otherwise, the user is a bum who gets the nasty message that he or she deserves.

confession.eps Figure 5-5 is a fake! To help you read the usernames and passwords, I added an extra statement to Listing 5-4. The extra statement (UIManager.put(“TextField.font”, new Font(“Dialog”, Font.BOLD, 14))) enlarges each text field’s font size. Yes, I modified the code before creating the figure. Shame on me!

Figure 5-5: Several runs of the code from Listing 5-4.

9781118128329 fg0505.tif

Listing 5-4 illustrates a new way to get user input; namely, to show the user an input dialog. The statement

String password =

JOptionPane.showInputDialog(“Password:”);

in Listing 5-4 performs more or less the same task as the statement

String password = keyboard.next();

from Listing 5-3. The big difference is, while keyboard.next() displays dull-looking text in a console, JOptionPane.showInputDialog(“Username:”) displays a fancy dialog box containing a text field and buttons. (Compare Figures 5-4 and 5-5.) When the user clicks OK, the computer takes whatever text is in the text field and hands that text over to a variable. In fact, Listing 5-4 uses JOptionPane.showInputDialog twice — once to get a value for the username variable, and a second time to get a value for the password variable.

Near the end of Listing 5-4, I use a slight variation on the JOptionPane business,

JOptionPane.showMessageDialog

(null, “You’re in.”);

With showMessageDialog, I show a very simple dialog box — a box with no text field. (Again, see Figure 5-5.)

Like thousands of other names, the name JOptionPane is defined in Java’s API. (To be more specific, JOptionPane is defined inside something called javax.swing, which in turn is defined inside Java’s API.) So to use the name JOptionPane throughout Listing 5-4, I import javax.swing.JOptionPane at the top of the listing.

tip.eps In Listing 5-4, JOptionPane.showInputDialog works nicely because the user’s input (username and password) are mere strings of characters. If you want the user to input a number (an int or a double, for example), you have to do some extra work. For example, to get an int value from the user, type something like int numberOfCows = Integer.parseInt(JOptionPane.showInputDialog(“How many cows?”)). The extra Integer.parseInt stuff forces your text field’s input to be an int value. To get a double value from the user, type something like double fractionOfHolsteins = Double.parseDouble(JOptionPane.showInputDialog(“Holsteins:”)). The extra Double.parseDouble business forces your text field’s input to be a double value.

Vive les nuls!

The French translations of For Dummies books are books Pour les Nuls. So a “dummy” in English is a “nul” in French. But in Java, the word null means “nothing.” When you see

if (

username != null

in Listing 5-4, you can imagine that you see

if (

username isn’t nothing

or

if (

username has any value at all

To find out how username can have no value, see the last row in Figure 5-5. When you click Cancel in the first dialog box, the computer hands null to your program. So in Listing 5-4, the variable username becomes null. The comparisons username != null checks to make sure that you haven’t clicked Cancel in the program’s first dialog box. The comparison password != null performs the same kind of check for the program’s second dialog box. When you see the if statement in Listing 5-4, you can imagine that you see the following:

if (

you didn’t press Cancel in the username dialog and

you didn’t press Cancel in the password dialog and

(

(you typed “bburd” in the username dialog) and

you typed “swordfish” in the password dialog)) or

(you typed “hritter” in the username dialog) and

you typed “preakston” in the password dialog))

)

)

warning_bomb.eps In Listing 5-4, the comparisons username != null and password != null are not optional. If you forget to include these and click Cancel when the program runs, you get a nasty NullPointerException message, and the program comes crashing down before your eyes. The word null represents nothing, and in Java, you can’t compare nothing to a string like “bburd” or “swordfish”. In Listing 5-4, the purpose of the comparison username != null is to prevent Java from moving on to check username.equals(“bburd”) whenever you happen to click Cancel. Without this preliminary username != null test, you’re courting trouble.

technicalstuff.eps The last couple of nulls in Listing 5-4 are different from the others. In the code JOptionPane.showMessageDialog (null, “You’re in.”), the word null stands for “no other dialog box.” In particular, the call showMessageDialog tells Java to pop up a new dialog box, and the word null indicates that the new dialog box doesn’t grow out of any existing dialog box. One way or another, Java insists that you say something about the origin of the newly popped dialog box. (For some reason, Java doesn’t insist that you specify the origin of the showInputDialog box. Go figure!) Anyway, in Listing 5-4, having a showMessageDialog box pop up from nowhere is quite useful.

(Conditions in parentheses)

Keep an eye on those parentheses! When you’re combining conditions with logical operators, it’s better to waste typing effort and add unneeded parentheses than to goof up your result by using too few parentheses. Take, for example, the expression

2 < 5 || 100 < 6 && 27 < 1

By misreading this expression, you might conclude that the expression is false. That is, you could wrongly read the expression as meaning (something-or-other) && 27 < 1. Because 27 < 1 is false, you would conclude that the whole expression is false. The fact is that, in Java, any && operator is evaluated before any || operator. So the expression really asks if 2 < 5 || (something-or-other). Because 2 < 5 is true, the whole expression is true.

To change the expression’s value from true to false, you can put the expression’s first two comparisons in parentheses, like this:

(2 < 5 || 100 < 6) && 27 < 1

tip.eps Java’s || operator is inclusive. This means that you get a true value whenever the thing on the left side is true, the thing on the right side is true, or both things are true. For instance, the expression 2 < 10 || 20 < 30 is true.

warning_bomb.eps In Java, you can’t combine comparisons the way you do in ordinary English. In English, you may say, “We’ll have between three and ten people at the dinner table.” But in Java, you get an error message if you write 3 <= people <= 10. To do this comparison, you need something like 3 <= people && people <= 10.

In Listing 5-4, the if statement’s condition has more than a dozen parentheses. What happens if you omit two of them?

if (

username != null &&

password != null &&

// open parenthesis omitted

(username.equals(“bburd”) &&

password.equals(“swordfish”)) ||

(username.equals(“hritter”) &&

password.equals(“preakston”))

// close parenthesis omitted

)

Java tries to interpret your wishes by grouping everything before the “or” (the || operator):

if (

username != null &&

password != null &&

(username.equals(“bburd”) &&

password.equals(“swordfish”))

||

(username.equals(“hritter”) &&

password.equals(“preakston”))

)

When the user clicks Cancel and username is null, Java says, “Okay! The stuff before the || operator is false, but maybe the stuff after the || operator is true. I’ll check the stuff after the || operator to find out if it’s true.” (Java often talks to itself. The psychiatrists are monitoring this situation.)

Anyway, when Java finally checks username.equals(“hritter”), your program aborts with an ugly NullPointerException message. You’ve made Java angry by trying to apply .equals to a null username. (Psychiatrists have recommended anger management sessions for Java, but Java’s insurance plan refuses to pay for the sessions.)

Building a Nest

Have you seen those cute Russian Matryoshka nesting dolls? Open up one, and another one is inside. Open up the second, and a third one is inside it. You can do the same thing with Java’s if statements. (Talk about fun!) Listing 5-5 shows you how.

Listing 5-5: Nested if Statements

import static java.lang.System.out;

import java.util.Scanner;

class Authenticator2 {

public static void main(String args[]) {

Scanner keyboard = new Scanner(System.in);

out.print(“Username: “);

String username = keyboard.next();

if (username.equals(“bburd”)) {

out.print(“Password: “);

String password = keyboard.next();

if (password.equals(“swordfish”)) {

out.println(“You’re in.”);

} else {

out.println(“Incorrect password”);

}

} else {

out.println(“Unknown user”);

}

}

}

Figure 5-6 shows several runs of the code in Listing 5-5. The main idea is that to log on, you have to pass two tests. (In other words, two conditions must be true.) The first condition tests for a valid username; the second condition tests for the correct password. If you pass the first test (the username test), you march right into another if statement that performs a second test (the password test). If you fail the first test, you never make it to the second test. Figure 5-7 shows the overall plan.

Figure 5-6: Three runs of the code in Listing 5-5.

9781118128329 fg0506.tif

Figure 5-7: Don’t try eating with this fork.

9781118128329 fg0507.eps

warning_bomb.eps The code in Listing 5-5 does a good job with nested if statements, but it does a terrible job with real-world user authentication. First, never show a password in plain view (without asterisks to masquerade the password). Second, don’t handle passwords without encrypting them. Third, don’t tell the malicious user which of the two words (the username or the password) was entered incorrectly. Fourth . . . well I could go on and on. The code in Listing 5-5 just isn’t meant to illustrate good username/password practices.

Choosing among Many Alternatives (Java switch Statements)

I’m the first to admit that I hate making decisions. If things go wrong, I would rather have the problem be someone else’s fault. Writing the previous sections (on making decisions with Java’s if statement) knocked the stuffing right out of me. That’s why my mind boggles as I begin this section on choosing among many alternatives. What a relief it is to have that confession out of the way!

Your basic switch statement

Now, it’s time to explore situations in which you have a decision with many branches. Take, for instance, the popular campfire song “Al’s All Wet.” (For a review of the lyrics, see the sidebar.) You’re eager to write code that prints this song’s lyrics. Fortunately, you don’t have to type all the words over and over again. Instead, you can take advantage of the repetition in the lyrics.

A complete program to display the “Al’s All Wet” lyrics won’t come until Chapter 6. In the meantime, assume that you have a variable named verse. The value of verse is 1, 2, 3, or 4, depending on which verse of “Al’s All Wet” you’re trying to print. You could have a big, clumsy bunch of if statements that checks each possible verse number.

if (verse == 1) {

out.println(“That’s because he has no brain.”);

}

if (verse == 2) {

out.println(“That’s because he is a pain.”);

}

if (verse == 3) {

out.println(“’Cause this is the last refrain.”);

}

But that approach seems wasteful. Why not create a statement that checks the value of verse just once and then takes an action based on the value that it finds? Fortunately, just such a statement exists. It’s called a switch statement. Listing 5-6 has an example of a switch statement.

Listing 5-6: A switch Statement

import static java.lang.System.out;

import java.util.Scanner;

class JustSwitchIt {

public static void main(String args[]) {

Scanner keyboard = new Scanner(System.in);

out.print(“Which verse? “);

int verse = keyboard.nextInt();

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;

default:

out.println(“No such verse. Please try again.”);

break;

}

out.println(“Ohhhhhhhh. . . .”);

}

}

Figure 5-8 shows two runs of the program in Listing 5-6. (Figure 5-9 illustrates the program’s overall idea.) First, the user types a number, like the number 2. Then, execution of the program reaches the top of the switch statement. The computer checks the value of the verse variable. When the computer determines that the verse variable’s value is 2, the computer checks each case of the switch statement. The value 2 doesn’t match the topmost case, so the computer proceeds on to the middle of the three cases. The value posted for the middle case (the number 2) matches the value of the verse variable, so the computer executes the statements that come immediately after case 2. These two statements are

out.println(“That’s because he is a pain.”);

break;

The first of the two statements displays the line That’s because he is a pain. on the screen. The second statement is called a break statement. (What a surprise!) When the computer encounters a break statement, the computer jumps out of whatever switch statement it’s in. So, in Listing 5-6, the computer skips right past the case that would display ’Cause this is the last refrain. In fact, the computer jumps out of the entire switch statement and goes straight to the statement just after the end of the switch statement. The computer displays Ohhhhhhhh. . . . because that’s what the statement after the switch statement tells the computer to do.

Figure 5-8: Running the code of Listing 5-6 two times.

9781118128329 fg0508.tif

If the pesky user asks for verse 6, the computer responds by dropping past cases 1, 2, and 3. Instead, the computer does the default. In the default, the computer displays No such verse. Please try again, and then breaks out of the switch statement. After the computer is out of the switch statement, the computer displays Ohhhhhhhh. . . .

Figure 5-9: The big fork in the code of Listing 5-6.

9781118128329 fg0509.eps

tip.eps You don’t really need to put a break at the very end of a switch statement. In Listing 5-6, the last break (the break that’s part of the default) is just for the sake of overall tidiness.

To break or not to break

In every Java programmer’s life, a time comes when he or she forgets to use break statements. At first, the resulting output is confusing, but then the programmer remembers fall-through. The term fall-through describes what happens when you end a case without a break statement. What happens is that execution of the code falls right through to the next case in line. Execution keeps falling through until you eventually reach a break statement or the end of the entire switch statement.

Usually, when you’re using a switch statement, you don’t want fall-through, so you pepper break statements throughout the switch statements. But, occasionally, fall-through is just the thing you need. Take, for instance, the “Al’s All Wet” song. (The classy lyrics are shown in the sidebar bearing the song’s name.) Each verse of “Al’s All Wet” adds new lines in addition to the lines from previous verses. This situation (accumulating lines from one verse to another) cries out for a switch statement with fall-through. Listing 5-7 demonstrates the idea.

Listing 5-7: A switch Statement with Fall-Through

import static java.lang.System.out;

import java.util.Scanner;

class FallingForYou {

public static void main(String args[]) {

Scanner keyboard = new Scanner(System.in);

out.print(“Which verse? “);

int verse = keyboard.nextInt();

switch (verse) {

case 3:

out.print(“Last refrain, “);

out.println(“last refrain,”);

case 2:

out.print(“He’s a pain, “);

out.println(“he’s a pain,”);

case 1:

out.print(“Has no brain, “);

out.println(“has no brain,”);

}

out.println(“In the rain, in the rain.”);

out.println(“Ohhhhhhhh...”);

out.println();

}

}

Figure 5-10 shows several runs of the program in Listing 5-7. Because the switch has no break statements in it, fall-through happens all over the place. For instance, when the user selects verse 2, the computer executes the two statements in case 2:

out.print(“He’s a pain, “);

out.println(“he’s a pain,”);

Then, the computer marches right on to execute the two statements in case 1:

out.print(“Has no brain, “);

out.println(“has no brain,”);

That’s good, because the song’s second verse has all these lines in it.

Figure 5-10: Running the code of Listing 5-7 four times.

9781118128329 fg0510.tif

Notice what happens when the user asks for verse 6. The switch statement in Listing 5-7 has no case 6 and no default, so none of the actions inside the switch statement are executed. Even so, with statements that print In the rain, in the rain and Ohhhhhhhh. . . right after the switch statement, the computer displays something when the user asks for verse 6.

Along comes Java 7

In Listings 5-6 and 5-7, the variable verse (an int value) steers the switch statement to one case or another. An int value inside a switch statement works in any version of Java, old or new. (For that matter, char values and a few other kinds of values have worked in Java’s switch statements ever since Java was a brand new language.)

But if you live in the fast lane and you’re using Java 7, you can set it up so that the case to be executed in a switch statement depends on the value of a particular string. Listing 5-8 illustrates the use of strings in switch statements. Figure 5-11 shows a run of the code in Listing 5-8.

Listing 5-8: A switch Statement with a String

import static java.lang.System.out;

import java.util.Scanner;

class SwitchIt7 {

public static void main(String args[]) {

Scanner keyboard = new Scanner(System.in);

out.print(“Which verse (one, two or three)? “);

String verse = keyboard.next();

switch (verse) {

case “one”:

out.println(“That’s because he has no brain.”);

break;

case “two”:

out.println(“That’s because he is a pain.”);

break;

case “three”:

out.println(“’Cause this is the last refrain.”);

break;

default:

out.println(“No such verse. Please try again.”);

break;

}

out.println(“Ohhhhhhhh. . . .”);

}

}

Figure 5-11: Running the code of Listing 5-8.

9781118128329 fg0511.tif

remember.eps If you’re using Java 6, or an older version of Java, then you can’t have a string decide the fate of a switch statement.

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

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