4.2 The switch Statement
The switch construct implements a multi-way branch that allows program control to be transferred to a specific entry point in the code of the switch block based on a computed value. Java has two variants of the switch construct (the switch statement and the switch expression), and each of them can be written in two different ways (one using the colon notation and the other using the arrow notation). This section covers the two forms of the switch statement. Particular details of the switch expression are covered in the next section (p. 164).
The switch Statement with the Colon (:) Notation
We will first look at the switch statement defined using the colon notation, illustrated in Figure 4.2.
Figure 4.2 Form of the switch Statement with the Colon Notation
switch (
selector_expression
) {
// Switch block with statement groups defined using colon notation:
case
CC
:
statements
case
CC
1
: case
CC
2
: … case
CC
n
:
statements
case
CC
3
,
CC
4
, …,
CC
m
:
statements
…
default: …
}
Conceptually, the switch statement can be used to choose one among many alternative actions, based on the value of an expression. The syntax of the switch statement comprises a selector expression followed by a switch block. The selector expression must evaluate to a value whose type must be one of the following:
- A primitive data type: char, byte, short, or int
- A wrapper type: Character, Byte, Short, or Integer
- An enum type (§5.13, p. 287)
- The type String (§8.4, p. 439)
Note that the type of the selector expression cannot be boolean, long, or floating-point. The statements in the switch block can have case labels, where each case label specifies one or more case constants (CC), thereby defining entry points in the switch block where control can be transferred depending on the value of the selector expression. The switch block must be compatible with the type of the selector expression, otherwise a compile-time error occurs.
The execution of the switch statement proceeds as follows:
- The selector expression is evaluated first. If the value is a wrapper type, an unboxing conversion is performed (§2.3, p. 45). If the selector expression evaluates to null, a NullPointerException is thrown.
- The value of the selector expression is compared with the constants in the case labels. Control is transferred to the start of the statements associated with the case label that has a case constant whose value is equal to the value of the selector expression. Note that a colon (:) prefixes the associated statements that can be any group of statements, including a statement block. After execution of the associated statements, control falls through to the next group of statements, unless this was the last group of statements declared or control was transferred out of the switch statement.
- If no case label has a case constant that is equal to the value of the selector expression, the statements associated with the default label are executed. After execution of the associated statements, control falls through to the next group of statements, unless this was the last group of statements declared or control was transferred out of the switch statement.
Figure 4.3 illustrates the flow of control through a switch statement where the default label is declared last and control is not transferred out of the switch statement in the preceding group of statements.
Figure 4.3 Activity Diagram for the switch Statement with the Colon Notation
All case labels (including the default label) are optional and can be defined in any order in the switch block. All case labels and the default label are separated from their associated group of statements by a colon (:). A list of case labels can be associated with the same statements, and a case label can specify a comma-separated list of case constants. At most, one default label can be present in a switch statement. If no valid case labels are found and the default label is omitted, the whole switch statement is skipped.
The case constants (CC) in the case labels are constant expressions whose values must be unique, meaning no duplicate values are allowed. In fact, a case constant must be a compile-time constant expression whose value is assignable to the type of the selector expression (§2.4, p. 46). In particular, all case constant values must be in the range of the type of the selector expression. The type of a case constant cannot be boolean, long, or floating-point.
The compiler is able to generate efficient code for a switch statement, as this statement only tests for equality between the selector expression and the constant expressions of the case labels, so as to determine which code to execute at runtime. In contrast, a sequence of if statements determines the flow of control at runtime, based on arbitrary conditions which might be determinable only at runtime.
In Example 4.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 piece of advice. Control then falls through to the statement at (3), giving the second piece of advice. Control next falls through to (4), dispensing the third piece of advice, and finally execution of 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—in this case, to the statement at (6) being executed. Execution of the break statement in a switch block transfers control out of the switch statement (p. 180). If the parameter howMuchAdvice has the value MORE_ADVICE, then the advice at both (3) and (4) is given. The value LITTLE_ADVICE results in only one piece of 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 group 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 statements for the case constant LITTLE_ADVICE in Example 4.1, which comprises statements (4) and (5).