Java provides selection statements that allow the program to choose between alternative actions during execution. The choice is based on criteria specified in the selection statement. These selection statements are
simple if Statement
if-else Statement
switch Statement
The simple if statement has the following syntax:
if (<conditional expression>)
<statement>
It is used to decide whether an action is to be performed or not, based on a condition. The condition is specified by <conditional expression> and the action to be performed is specified by <statement>.
The semantics of the simple if statement are straightforward. The <conditional expression> is evaluated first. If its value is true, then <statement> (called the if block) is executed and execution continues with the rest of the program. If the value is false, then the if block is skipped and execution continues with the rest of the program. The semantics are illustrated by the activity diagram in Figure 5.1a.
In the following examples of the if statement, it is assumed that the variables and the methods have been defined appropriately:
if (emergency) // emergency is a boolean variable operate(); if (temperature > critical) soundAlarm(); if (isLeapYear() && endOfCentury()) celebrate(); if (catIsAway()) { // Block getFishingRod(); goFishing(); }
Note that <statement> can be a block, and the block notation is necessary if more that one statement is to be executed when the <conditional expression> is true.
Since the <conditional expression> must be a boolean expression, it avoids a common programming error: using an expression of the form (a=b) as the condition, where inadvertently an assignment operator is used instead of a relational operator. The compiler will flag this as an error, unless both a and b are boolean.
Note that the if block can be any valid statement. In particular, it can be the empty statement (;) or the empty block ({}). A common programming error is an inadvertent use of the empty statement.
if (emergency); // Empty if block operate(); // Executed regardless of whether it was an emergency or not.
The if-else statement has the following syntax:
if (<conditional expression>)
<statement1>
else
<statement2>
It is used to decide between two actions, based on a condition.
The <conditional expression> is evaluated first. If its value is true, then <statement1> (the if block) is executed and execution continues with the rest of the program. If the value is false, then <statement2> (the else block) is executed and execution continues with the rest of the program. In other words, one of two mutually exclusive actions is performed. The else clause is optional; if omitted, the construct reduces to the simple if statement. The semantics are illustrated by the activity diagram in Figure 5.1b.
In the following examples of the if-else statement, it is assumed that all variables and methods have been defined appropriately:
if (emergency) operate(); else joinQueue(); if (temperature > critical) soundAlarm(); else businessAsUsual(); if (catIsAway()) { getFishingRod(); goFishing(); } else playWithCat();
Since actions can be arbitrary statements, the if statements can be nested.
if (temperature >= upperLimit) { // (1) if (danger) // (2) Simple if. soundAlarm(); if (critical) // (3) evacuate(); else // Goes with if at (3). turnHeaterOff(); } else // Goes with if at (1). turnHeaterOn();
The use of the block notation, {}, can be critical to the execution of if statements. The if statements (A) and (B) in the following examples do not have the same meaning. The if statements (B) and (C) are the same, with extra indentation used in (C) to make the meaning evident. Leaving out the block notation in this case could have catastrophic consequences: the heater could be turned on when the temperature is above the upper limit.
// (A) if (temperature > upperLimit) { // (1) Block notation. if (danger) soundAlarm(); // (2) } else // Goes with if at (1). turnHeaterOn(); // (B) if (temperature > upperLimit) // (1) Without block notation. if (danger) soundAlarm(); // (2) else turnHeaterOn(); // Goes with if at (2). // (C) if (temperature > upperLimit) // (1) if (danger) // (2) soundAlarm(); else // Goes with if at (2). turnHeaterOn();
The rule for matching an else clause is that an else clause always refers to the nearest if that is not already associated with another else clause. Block notation and proper indentation can be used to make the meaning obvious.
Cascading if-else statements are a sequence of nested if-else statements where the if of the next if-else statement is joined to the else clause of the previous one. The decision to execute a block is then based on all the conditions evaluated so far.
if (temperature >= upperLimit) { // (1) soundAlarm(); turnHeaterOff(); } else if (temperature < lowerLimit) { // (2) soundAlarm(); turnHeaterOn(); } else if (temperature == (upperLimit-lowerLimit)/2) { // (3) doingFine(); } else // (4) noCauseToWorry();
The block corresponding to the first if condition that evaluates to true is executed, and the remaining ifs are skipped. In the example given above, the block at (3) will execute only if the conditions at (1) and (2) are false and the condition at (3) is true. If none of the conditions are true, the block associated with the last else clause is executed. If there is no last else clause, no actions are performed.
Conceptually the switch statement can be used to choose one among many alternative actions, based on the value of an expression. Its general form is as follows:
switch (<non-long integral expression>) {
case label1: <statement1>
case label2: <statement2>
...
case labeln: <statementn>
default: <statement>
} // end switch
The syntax of the switch statement comprises a switch expression followed by the switch body, which is a block of statements. The type of the switch expression is non-long integral (i.e., char, byte, short, or int). The statements in the switch body can be labeled, defining entry points in the switch body where control can be transferred depending on the value of the switch expression. The semantics of the switch statement are as follows:
The switch expression is evaluated first.
The value of the switch expression is compared with the case labels. Control is transferred to the <statementi> associated with the case label that is equal to the value of the switch expression. After execution of the associated statement, control falls through to the next statement unless appropriate action is taken.
If no case label is equal to the value of the switch expression, the statement associated with the default label is executed.
Figure 5.2 illustrates the flow of control through a switch statement.
All labels (including the default label) are optional and can be defined in any order in the switch body. There can be at most one default label in a switch statement. If it is left out and no valid case labels are found, the whole switch statement is skipped.
The case labels are constant expressions whose values must be unique, meaning no duplicate values are allowed. The case label values must be assignable to the type of the switch expression (see Section 3.4, p. 48). In particular, the case label values must be in the range of the type of the switch expression. Note that the type of the case label cannot be boolean, long, or floating-point.
public class Advice { public final static int LITTLE_ADVICE = 0; public final static int MORE_ADVICE = 1; public final static int LOTS_OF_ADVICE = 2; public static void main(String[] args) { dispenseAdvice(LOTS_OF_ADVICE); } public static void dispenseAdvice(int howMuchAdvice) { switch(howMuchAdvice) { // (1) case LOTS_OF_ADVICE: System.out.println("See no evil."); // (2) case MORE_ADVICE: System.out.println("Speak no evil."); // (3) case LITTLE_ADVICE: System.out.println("Hear no evil."); // (4) break; // (5) default: System.out.println("No advice."); // (6) } } }
Output from the program:
See no evil. Speak no evil. Hear no evil.
In Example 5.1, depending on the value of the howMuchAdvice parameter, different advice is printed in the switch statement at (1) in the method dispenseAdvice(). The example shows the output when the value of the howMuchAdvice parameter is LOTS_OF_ADVICE. In the switch statement, the associated statement at (2) is executed, giving one advice. Control then falls through to the statement at (3), giving the second advice. Control falls through to (4), dispensing the third advice, and finally executing the break statement at (5) causes control to exit the switch statement. Without the break statement at (5), control would continue to fall through the remaining statements if there were any. Execution of the break statement in a switch body transfers control out of the switch statement (see Section 5.4, p. 172). If the parameter howMuchAdvice has the value MORE_ADVICE, then the advice at (3) and (4) is given. The value LITTLE_ADVICE results in only one advice at (4) being given. Any other value results in the default action, which announces that there is no advice.
The associated statement of a case label can be a list of statements (which need not be a statement block). The case label is prefixed to the first statement in each case. This is illustrated by the associated statement for the case label LITTLE_ADVICE in Example 5.1, which comprises statements (4) and (5).
Example 5.2 makes use of a break statement inside a switch statement to convert a char value representing a digit to its corresponding word in English. Note that the break statement is the last statement in the list of statements associated with each case label. It is easy to think that the break statement is a part of the switch statement syntax, but technically it is not.
public class Digits { public static void main(String[] args) { System.out.println(digitToString('7') + " " + digitToString('8') + " " + digitToString('6')); } public static String digitToString(char digit) { String str = ""; switch(digit) { case '1': str = "one"; break; case '2': str = "two"; break; case '3': str = "three"; break; case '4': str = "four"; break; case '5': str = "five"; break; case '6': str = "six"; break; case '7': str = "seven"; break; case '8': str = "eight"; break; case '9': str = "nine"; break; case '0': str = "zero"; break; default: System.out.println(digit + " is not a digit!"); } return str; } }
Output from the program:
seven eight six
Several case labels can prefix the same statement. They will all result in the associated statement being executed. This is illustrated in Example 5.3 for the switch statement at (1).
The first statement in the switch body must have a case label, or it is unreachable. This statement will never be executed since control can never be transferred to it. The compiler will flag this as an error.
Since each action associated with a case label can be an arbitrary statement, it can be another switch statement. In other words, switch statements can be nested. Since a switch statement defines its own local block, the case labels in an inner block do not conflict with any case labels in an outer block. Labels can be redefined in nested blocks, unlike variables which cannot be redeclared in nested blocks (see Section 4.5, p. 123). In Example 5.3, an inner switch statement is defined at (2). This allows further refinement of the action to take on the value of the switch expression, in cases where multiple labels are used in the outer switch statement. A break statement terminates the innermost switch statement in which it is executed.
public class Seasons { public static void main(String[] args) { int monthNumber = 11; switch(monthNumber) { // (1) Outer case 12: case 1: case 2: System.out.println("Snow in the winter."); break; case 3: case 4: case 5: System.out.println("Green grass in spring."); break; case 6: case 7: case 8: System.out.println("Sunshine in the summer."); break; case 9: case 10: case 11: // (2) switch(monthNumber) { // Nested switch (3) Inner case 10: System.out.println("Halloween."); break; case 11: System.out.println("Thanksgiving."); break; } // end nested switch // Always printed for case labels 9, 10, 11 System.out.println("Yellow leaves in the fall."); // (4) break; default: System.out.println(monthNumber + " is not a valid month."); } } }
Output from the program:
Thanksgiving. Yellow leaves in the fall.