home—info—lects—labs—exams—hws
textbook—tutor/PIs—java.lang docs—java.util docs
lect06c
Nesting if-else
nesting if-elses
In yesterday's lab,
we used if-else to distinguish
two different cases:
an order for exactly one donut (singular),
and
orders for any other number (0, or 2+).
Here is a similar yet different method;
you can imagine that the chef in the back tells the computer
how many slices of pizza are available of a certain type,
and then the computer has to create a message which gets
displayed up front (on an LED screen, or billboard, or a spammail, or …)
/** Given how many slices of (say) mushroom pizza are
* currently available, create a nice tempting message to
* advertise (shout out, or post, or put on a LED sign...)
*
* @param topping The type of pizza (e.g. "pepperoni")
* @param slicesReady The number of currently ready-to-serve
* slices with the given topping.
* @return A complete sentence describing the inventory.
* For example:
* inventoryMessage( "mushroom", 3 )
* = "There are 3 piping hot pieces of mushroom pizza, ready to eat!"
*/
String slicesReadyMsg( String topping, int slicesReady ) {
String msg;
if (slicesReady == 1) {
msg = "There is "
+ slicesReady
+ " piping hot slice of "
+ topping
+ " pizza, ready to eat!";
}
else {
msg = "There are "
+ slicesReady
+ " piping hot slices of "
+ topping
+ " pizza, ready to eat!";
}
return msg;
}
|
That was fine for a first attempt, but can we
separately handle all three
categories of 0, 1, and “more”,
using just the syntax for
if-else?
if (condition) {
statements…
}
else {
statements…
}
|
Yes:
// (See above for comments)
String slicesReadyMsg( String topping, int slicesReady ) {
String msg;
if (slicesReady == 1) {
msg = "There is "
+ slicesReady
+ " piping hot slice of "
+ topping
+ " pizza, ready to eat!";
}
else { // slicesReady isn't equal to 1
if (slicesReady ==0) {
msg = "We are momentarily out of " + topping + " pizzas.";
}
else {
msg = "There are "
+ slicesReady
+ " piping hot slices of "
+ topping
+ " pizza, ready to eat!";
}
}
return msg;
}
|
We see that if-else statements
are themselves a type of statement,
therefore they can be put inside (other) if-elses!
It's worth mentioning specially, that indentation starts becoming
extremely important, to people reading your programs:
it would be very easy to mislead people about what your program
is doing, by being careless about indenting.
After all, we had an if-else statement
inside of another else clause, but it could conceivably
also be written inside the if clause.
Curly-brackets tell the computer what contains what else,
but indentation is what tells humans how the code is structured.
(If your code makes me stop to think about whether its visual structure
matches what it really does, you will lose points.)
This idea of nesting an if-else statment
inside another else clause
is actually very common; it happens whenever we need to choose between
more than two equal options.
While what we wrote makes sense, it's annoying for two reasons:
-
If we have seventeen equal options we're choosing between,
our code will “rightward drift” right off the screen.
-
More disturbingly, our code won't reflect how we think about the
problem: if all seventeen options are equally important,
why should some options contain the others, just because
we consider them in some particular order?
(“last” does not have to mean “least”!)
In response to these common concerns, Java includes a
variant of the if-else statement,
call the if-else-if statement.
Here's an example:
/** Return a greeting, selected randomly from a list of several greetings.
* @return A greeting (randomly selected, not necessarily uniformly).
*/
String greet() {
int choice = (new java.util.Random()).nextInt(100);
// Instances of `Random` have a method `nextInt(n)`,
// which returns a number in [0,n) = {0,1,2,...,n-1}.
String msg;
if (choice < 30) {
msg = "Hello.";
}
else if (choice < 33) {
msg = "Aloha.";
}
else if (choice < 50) {
msg = "Buenos dias, amigo/amiga.";
}
else if (choice < 99) {
msg = "Yo.";
}
else if (choice < 100) {
// Not an advisable greeting. Use sparingly.
msg = "I am a javabot: System dot out dot println open \"hello\" close.";
}
else {
System.err.println( "Uh-oh, I didn't expect to reach here!" );
msg = "A dummy initialiazation for `msg`, to appease the compiler.";
}
return msg;
}
|
Some discussions:
-
The return statement means
“stop this function right now, and return an answer”.
Thus1
the line at the end will never actually be reached,
because one of the return statements will be selected
first.
- If choice is initialized with the value 30,
what number is returned? How about 34?
- What is the probability of returning Hello?
How about Aloha?
Half-open intervals make this answer easy
(no having to decide whether add one or to subtract one)!
- Is the choice < 100 branch actually ever taken?
- What if we change “< 100”
to “<= 100”?
- What if we change “< 99”
to “<= 99”?
- If we leave off the “appeasing” return statement,
the program doesn't compile; java complains “possible to
reach end of function without a return statement”.
Why?
Discuss.
- More fundamentally:
Should the if (choice < 100) be omitted, so that it is
the catch-all else?
Consider—what if we have some mistake in our series of cases (say,
accidentally leaving off the case, for some intermediate range of numbers)?
Can the compiler catch such a mistake automatically?
guideline:
If your last condition is easy to phrase (as it is here),
then certainly include it,
making the last else unreachable.
But don't bend over backwards, to do this; sometimes formulating
that final condition is more error-prone than the savings you'd get!
Mention:
Arguably, it is bad to have more than one return in a method;
(rather than always reaching the end of the method and returning a value there,
for everybody to easily see).
I don't insist on this, but you may have later teachers who do.
Technicalities
-
In an
if-else statement,
Java allows you to leave off the last else,
if the curly-brackets would be empty.
-
When you need to update a field conditionally,
it's common to have an if without an else.
-
However,
when the purpose of the entire
if-else(-if) statement
is to
return an answer or to initialize a variable,
I suggest that you do include an else branch,
and make sure that each branch
either returns or initializes.
(That keeps it clear what the purpose of the entire
if-else statement is.)
Again, here's a version of the previous code where
we've factored out the common part,
and just initialize local variables with the 'variant' part:
String slicesReadyMsg( String topping, int slicesReady ) {
String verbForm; // The correct verb for our result.
String plurality; // The noun-suffix, correctly plural or singular.
if (numInStock == 1) {
verbForm = "is";
plurality = "";
}
else {
verbForm = "are";
plurality = "s";
}
return "There " + verbForm + " "
+ slicesReady +
+ " piping hot slices of "
+ topping + ("pizza" + plurality)
+ " in stock.";
}
|
You will see, though,
other people use arguably poorer style,
where they
initialize a variable to a potentially-wrong value,
and then go back and correct it when needed:
String slicesReadyMsg( String topping, int slicesReady ) {
String verbForm = "are"; // The correct verb for our result.
String plurality = "s"; // The noun-suffix, correctly plural or singular.
// Note that at this moment, our variables may or may
// hold their correct values.
if (numInStock == 1) {
verbForm = "is";
plurality = "";
} // `if` without `else` is legal Java.
return "There " + verbForm + " "
+ slicesReady +
+ " piping hot slices of "
+ topping + ("pizza" + plurality)
+ " in stock.";
}
|
In this version, you can't point to a single statement which initializes
the variable;
people maintaining this code in the future
might miss the 'second initialization',
if they need to alter the initialization.
-
When there is only a single statement in the body (between the curly-braces),
the book reveals that you can conceivably omit the curly-brackets.
2
optional:
The following explanation is optional, and will be skipped in lecture,
as long as you read the concluding
edict below.)
Alas, omitting the brackets is bad for several reasons:
-
It's fairly common that you decide later to go back and add
something to the if- or else- case, and you end up adding the brackets
later.
Moreover, if you have several lines in a block and delete them down
to just one, you'd want to delete the brackets to be consistent
(and not cause readers to wonder if there is some unintentional bug).
-
This usually leads to confusion though, and the book has to spend
several minutes talking about dangling elses.
-
Consider:
if (numInStock == 1)
verbForm = "is";
else
verbForm = "are";
|
What if we go back, and decide to add the lines for plurality,
but we forget to put in curly-braces?:
if (numInStock == 1)
verbForm = "is";
plurality = ""; // DANGER, WILL ROBINSON!
else
verbForm = "are";
plurality = "s";
|
Java gives an error “else without an if” -- why?
If we hadn't had any else statement at all,
would we have caught our error?
Edict:
Even if you have only one line inside
an if- or else- block,
include curly-braces.
One exception:
-
If the statement is so short it easily fits on the same line
as the if or else keyword, you
can put it on the same line (without curly-braces).
(But don't be surprised if you find yourself later going back
and adding more to that line, which will then require the curly-braces.)
1
So we could conceivably use
a series of if statements (without else),
rather than a big if-else.
The second if statement is only reached when the
first condition wasn't true (because in that case we'd return
before ever reaching the second if condition).
↩
2So really, the actual syntax for Java's if-else statement is
if (condition)
statement
else
statement
|
This is actually a general case of the version-with-brackets, given in these notes.
Why? Because along with assignment statments and return statements
and if statements, there is a block statement,
which looks like { statements… }.
↩
home—info—lects—labs—exams—hws
textbook—tutor/PIs—java.lang docs—java.util docs