It would be wonderful if every decision
could be reduced to a single "either-or" choice that could be solved
with a simple
if-else statement; it would sure make
Most of the time, though, things are more complex, and you'll
need to write selection statements involving three, four, five
or more alternatives. Just writing a program to calculate your
income tax, for instance, using the tax tables, involves dealing
with literally hundreds of different alternatives.
To solve these kinds of programs you'll need to learn how to use one of Java's multi-way branching statements:
Let's start by looking at sequential
if statements, which
are used when you have a sequence of related
Sequential If Statements
One sequential comparison that you're all familiar with is the "letter grading scale" used to assign marks in school, (including in this course), similar to that shown in the table to the right.
Typically, your letter grade is based on a percentage representing the weighted average for all of the work you've done during the term. In the example shown here, for instance, those who earn 90% or greater receive 'A's, those with percentages less than 90%, but at least 80% earn 'B's, and so on.
To explore sequential comparisons I'll use a simple example program named GradeCalculator.java which you'll find in this chapter's code folder. Open it up and follow along in DrJava if you want to experiment as we go.
If you run the program, you'll see that it:
- asks for the student's name and the number of scores to record.
- requests the possible points and the points earned for each of the scores.
- calculates and prints the percentage score and the letter grade for the student.
As you can see here, I've run the program for a student named Fred. I entered two 100-point test scores and a 15-point quiz score and the program correctly calculates Fred's percentage score (79.1%). However, it doesn't yet handle the letter grade. That's our next stop.
Before we get there, though, let's take a look at what we've got; we'll read through the program together, and then we'll look at several different ways we can implement the code for calculating the letter grade.
The GradeCalculator Program
Here's how the program works:
- Lines 19 and 20 print a heading for the program,
and then lines 23 and 24 create a
studentand has the user initialize it by reading the student's name. Lines 25 and 26 create an
numScoresand has the user initialize it by reading the number of scores to record.
- Lines 29 and 30 define the accumulators for the
program. As each score is entered, that score will be added to
pointsEarnedvariables. I made these variables
intso the teacher could assign half points.
- Next, we need to get the input for each exam,
quiz or lab, which we'll do by using the
forloop. Notice that we repeat the input actions a fixed number of times, based on the value of the variable
After all of the input is done, the points earned and the possible points are added up and the result printed.
- After the loop, line 48 uses the possible points and
the points earned to calculate the student's percentage grade.
This is done by calling the
getPercentage()function, which we'll look at shortly.
Then, line 49 defines the
letterGradeand initializes it by calling the function
percentvariable initialized in the previous line.
- Finally, the
main()method ends by printing the formatted output in the statement that spans lines 52-53. The output consists of the student's name, left-aligned in a 40-character-wide field, the student's percentage grade (formatted to 1 significant decimal), and the letter grade.
Now, let's look at the two functions.
The getPercentage() Function
getPercentage() method returns the
student's current numeric grade, as a percentage as the
name implies. There function takes two
representing the possible points and the points that the student has earned.
The method uses a simple
statement to avoid the problem of returning the NaN value
when dividing by floating-point zero if a student
hasn't yet taken any exams and 0.0 is passed as the
possible parameter. (If the parameter were an
int instead of a
double, you'd still
if-else statement do avoid the runtime
error that occurs with an integer divide-by-zero.)
else clause, the percentage returned is
multiplied by 100.0 so that we'll deal with numbers like 79.0,
The getLetterGrade() Function
The final portion of code we want to look at is
getLetterGrade() which returns the letter grade based on
the student's current percentage score. As you can see here, the function
currently returns the phrase "NOT DEFINED":
Multiway Selection Techniques
Now let's look at several techniques for implementing the
Method 1: Independent if Statements
The first technique is to use the logical operators to combine
several conditions using independent
Here's what the code would look like in this version of
Here's how the method works:
- Since this is a
Stringoutput variable named
resultis created and initialized to the empty
String. Then, the literal "NOT DEFINED" in the
returnstatement is replaced with the variable
- Next, the current numeric percentage is
compared against each range, using the && operator
to check the lower and upper bound for the range. I've used the
percentage cutoffs for a common course. (Since each
ifbody contains only a single statement, I've also used the single-line formatting technique that I mentioned in the last unit.)
- Finally, before returning the result, the function makes sure that any invalid input is reported as well.
While this solution is correct, it's also longer than it needs to be and it's quite inefficient. Each time the function is called, all six Boolean selection conditions are tested, even after the correct one has been found.
The problem is, the solution uses independent
if statements, while the conditions themselves are
actually interdependent. If someone gets an "A", then it is
not possible for them to also, and at the same time, get an "F".
if statements are designed for processing
conditions where each condition could be independently true,
and not really affect any other condition, like the code you'd use
to process the checkboxes on a form like that shown here.
With a form like this, the user may select any number of options,
(or none at all), but each option doesn't affect the others. That
means you must check each one, and the only way to do
that is by using independent
Method 2: Using Multiple Selection
A better solution, when you need to select one course of action from many possible alternatives (which is the case here), is to employ what Rick Mercer at Arizona State calls the "Multiple Selection Algorithmic Pattern", shown here. An "algorithmic pattern" is simply a recipe for solving a particular category of problem.
This particular pattern is also often called a ladder style
if statement, because each of the conditions are formatted
one under the other, like the rungs on a ladder. It is also sometimes
if-else-if statement. (Note though that the
else if keywords are not combined into a single
elseif, as in some other languages, such as
Visual Basic, or the
elif keyword in Python.)
Here's the code for this second version of
using the multiple-selection (or sequential
if) pattern :
- With the multiple-selection pattern, we need to move our error checking to the beginning of the routine from the end, since each test depends on the one that precedes it. If we left the error checking at the end of the method, it would never be executed, and the method would return an incorrect value. In the example shown here, I've used concatenation to display the percent value that causes the problem, along with the error message.
- On the following lines, only the lower bounds of each
category is tested. By the time we reach line 86, we already know
that the percentage falls between 0% and 100%, so we only have
to check if it is at least 90% to assign the value for an "A".
The same pattern continues on lines 87 through 89. On line 87, we know that the percentage is less than 90, since we just checked it on the previous lines. So, we don't need to check it again, like we did with the independent
- Finally, the last "rung" in the ladder doesn't need an
ifportion. The only thing left is the range from 0 to 49, so you can use a plain
A Pitfall to Watch For
While the multiple-selection pattern is much more efficient than
if statements, each of the statements
is dependent on the one that comes before it. That means that
the order of the statements is significant.
If you switch the order of the "A" and "B" tests, for instance, like this:
else if (percent >= 80) result = "B";
else if (percent >= 90) result = "A";
all of those students who should
have gotten "A"s, will get "B"s instead, since a score of 95 matches
(percent >= 80) and that condition is
now encountered before the condition that tests for an "A".
The test for an "A" will never be executed.
Try It Yourself
Go ahead and try it out. Complete the
and then run it with inputs for each possibility (A-F along with out of range).
Nested If Statements
As you just saw, you can code decisions involving multiple alternatives in two different ways:
- by writing independent
ifstatements that combine their different
booleanconditions using the AND and the OR operators.
- by arranging your
ifstatements in a ladder-like sequence of related, dependent
A third way to do the same thing is through nesting.
Nesting means that one
if statement is
embedded or nested inside the body of another
if statement, much like the traditional Russian
nesting dolls, shown here.
can appear in the body of the
if portion of an
else statement, in the body of
else portion, or inside both.
if statements are used whenever you need to
test for different levels of decision making, rather than
a set of purely sequential tests. If you're one of those fortunate
folks making more than a hundred thousand dollars a year, for instance,
you'll need to calculate your taxes using the following formula,
instead of using the tax tables:
|Filing Status : Single||Filing Status: Married Filing Jointly|
|Taxable Income||Tax||Taxable Income||Tax|
|$100,000 ... $146,750||28% less $5,373||$100,000 ... $117,250||25% less $6,525|
|$146,751 ... $319,100||33% less $12,710.50||$117,251 ... $178,650||28% less $10,042.50|
|Over $319,100||35% less $19,092.50||$178,651 ... $319,100||33% less $18,975|
|Over $319,100||35% less $25,357|
|Filing Status : Married Filing Separately||Filing Status: Head of Household|
|Taxable Income||Tax||Taxable Income||Tax|
|$100,000 ... $159,550||33% less $9,487.50||$100,000 ... $100,500||25% less $4,400|
|Over $159,550||35% less $12,678.50||$100,501 ... $162,700||28% less $7,415|
|$162,701 ... $319,100||33% less $15,550|
|Over $319,100||35% less $21,932|
Suppose that you were single, with a taxable income of $159,750. To calculate your tax, you'd first locate the schedule for your filing status (Single), and then locate the bracket you fall into (the second). Your tax would be $159,750 x 33% less $12,710.50.
If you wanted to write a program to perform this calculation,
you'd need to follow a similar set of steps. You'd first need to use a set
if statements to determine
which set of calculations to use, like this:
if (status == SINGLE)
// calculate the tax for a single taxpayer
else if (status == MARRIED_JOINT_FILE)
// calculate for a joint-filing married taxpayer
else if (status == MARRIED_SINGLE_FILE)
// calculate for a single-filing married taxpayer
else if (status == HEAD_OF_HOUSEHOLD)
// calculate for a head-of-household taxpayer
Then, nested inside the body of each portion of each
statement, you'd test the various income levels, like this:
if (taxableIncome <= SINGLE_BRACKET1)
tax = taxableIncome * SINGLE_RATE1 - SINGLE_EX1;
else if (taxableIncome <= SINGLE_BRACKET2)
tax = taxableIncome * SINGLE_RATE2 - SINGLE_EX2;
tax = taxableIncome * SINGLE_RATE3 - SINGLE_EX3;
else if (status == MARRIED_JOINT_FILE)
// calculate the tax for a married taxpayer
Nesting Pitfalls: The Dangling else
When you nest one
if statement inside of another,
if statement won't always have an
portion. When this occurs, it's possible for the
of the enclosing block to inadvertently "attach itself" to the inner
if statement. This is known as the dangling else
Here's an example. In the code shown in the screenshot, the programmer
intended to allow children 12 and under to "get in free" (the
branch of the first
if statement. A nested
was intended to provide a "senior citizens" discount as well.
Everyone else was supposed to pay full price.
When the code is run, though, the result is exactly the opposite. Because the
else clause automatically attaches itself to the closest unmatched
if statement, the young kids all pay full price, while all of
the pre-senior adults get in for free.
Avoiding this problem is really pretty easy: whenever you use nested
statements, always enclose the body of both the
portions in braces. The braces act like a "fence" that keeps the
portions where they belong.
The switch Statement
Both the nested
if statements and the ladder-style
provide you with the tools you need to do
multi-way branches. But there's still one more
multi-way selection tool
that you should have in your programming toolbox.
Another Java control structure, the
provides an even more efficient way to select between several
different alternatives, provided you can live with its
limitations and somewhat idiosyncratic behavior.
Many other languages have a multi-way branch statement,
usually called a
case statement. If you've programmed in
one of these different languages, you might find the term
switch a little unusual. The name seems much more
logical, however, if you think of a railway switching yard or
a telephone switchboard, rather than a light-switch.
switch statement is different than
else statement because the
switch is based upon an integer evaluation,
rather than upon a
Let's briefly look at the syntax of the
statement and then we'll take a look at how it works.
Here's an illustration that shows the syntax of the
As you can see, the
consists of five different parts.
switchkeyword, followed by an integral expression enclosed in parentheses. This expression is called the switch selector. The selector can be a variable or any expression, as long as the type of the expression is
char. You cannot use floating-point,
Stringselectors. (The upcoming Java 7, will allow
Stringselectors, however.) The body of the
switchstatement, which follows, is enclosed in braces.
- Any number of
caselabel consists of the keyword
case, followed by a constant integral expression. The
caselabel ends with a colon, not a semicolon.
- Any number of statements following each
caselabel. These do not have to be enclosed in braces as with a loop or
breakstatement to end each
default:label to handle the unmatched cases.
Let's look at each of these pieces to see how they work together.
How it works
switch statement is encountered, the
first thing that happens is that its switch selector, or
integer "test" expression is evaluated. After the test expression is
evaluated the following steps are performed:
- The list of labeled constants is scanned, looking
for a match. If an exact match is found:
- Java begins executing the first line of code immediately
following the matching
- Each line of code following the
caselabel is executed sequentially until either a
breakstatement is encountered or all of the statements in the
switchbody have been executed.
- Java begins executing the first line of code immediately following the matching
- If no match is found, then execution jumps to the
statement following the
default:label, if one was supplied.
- If no match is found and there is no
default:label, then execution jumps to the first statement following the
A Simple Example
A very common use for a
switch statement is to
implement a menu. Let's create a simple menu that allows the
user to select 1) for Twinkies, and 2) for Tofu; something
for everyone. Here's the code:
You can find this in the program SimpleMenuSwitch.java in this chapter's code folder. Let's look at the code:
- The first section of the program creates a
Scannerobject for input and then prints a menu.
- After printing the menu, the program creates an
choiceand allows the user to initialize it.
choicevariable is used as the switch selector.
switchstatement can evaluate
int, byte, short, or char selection values. It will not work with double, long,
String, or any object types.
- Each case label contains a constant
value to be matched against the switch selector.
The value stored in
choicewill be compared to each of the case label values and if an exact match is found, the program will jump to the first line of code in that block.
- Each case block should (almost always) end with
breakstatement. If you don't have a
breakthen control will continue to the next case block, even if the selector does not match that block's case label.
- Finally, if you want to do something if the switch
selector fails to match any case, then you can add an optional
defaultblock. This block is traditionally placed last (which is why I haven't included a
breakstatement). If you don't have a
defaultblock then nothing would happen at all when the user entered an invalid selection.
Here's what the program looks like as it runs:
There are two common problems students encounter when learning
to use the
The first problem has to do with the
case label must include:
- A constant integer expression (not including
long), followed by a colon.
- This means you can't use variables,
Stringsor ranges as part of your
The second problem has to do with forgetting to use
break statement. If you don't include a
break statement, then all of the statements in
switch body, following your
are executed as well. This is called fall through and is
a very common programming error when using a
Multi-way Branches Summary
ifstatements should only be used when each condition is truly independent.
- Sequential or ladder-style
ifstatements allow you to efficiently choose one from several different interdependent conditions. This structure is also known as the Multiple-Selection Algorithmic Pattern.
- One pitfall of sequential
ifstatements, is that the order of the conditions is critical. Placing an item out of order can result in an incorrect test.
- When you have different levels of testing, then the best kind
of structure is a set of nested
- A common pitfall with nested
ifstatements is having a nested
else, where an "outer"
elseclause attaches itself to the "inner"
if. Using braces on all nested
ifstatements will eliminate this problem.
switchstatement is a multiway branch that relies on matching labeled blocks of code with an integral expression. Instead of a Boolean condition, an implicit equality check is made to each label, and an unconditional jump is performed if a match is found.
switchselector, or variable that is evaluated, must be one of the integer types (not including
- The case labels used to identify each code block must be literals or constants, followed by a colon (not a semicolon).
defaultblock, if supplied, is executed when no case matches the selector.
- You must supply a
breakstatement to terminate each case block. If you don't, then execution falls through to the following case blocks.