switch
The switch is sometimes classified as a selection statement. The switch statement selects from among pieces of code based on the value of an integral expression. Its form is:
switch(integral-selector) {
case integral-value1 : statement; break;
case integral-value2 : statement; break;
case integral-value3 : statement; break;
case integral-value4 : statement; break;
case integral-value5 : statement; break;
// ...
default: statement;
}
Integral-selector is an expression that produces an integral value. The switch compares the result of integral-selector to each integral-value. If it finds a match, the corresponding statement (simple or compound) executes. If no match occurs, the default statement executes.
You will notice in the preceding definition that each case ends with a break, which causes execution to jump to the end of the switch body. This is the conventional way to build a switch statement, but the break is optional. If it is missing, the code for the following case statements execute until a break is encountered. Although you don’t usually want this kind of behavior, it can be useful to an experienced programmer. Note that the last statement, following the default, doesn’t have a break because the execution just falls through to where the break would have taken it anyway. You could put a break at the end of the default statement with no harm if you considered it important for style’s sake.
The switch statement is a clean way to implement multiway selection (i.e., selecting from among a number of different execution paths), but it requires a selector that evaluates to an integral value, such as int or char. If you want to use, for example, a string or a floating-point number as a selector, it won’t work in a switch statement. For non-integral types, you must use a series of if statements.
Here’s an example that creates letters randomly and determines whether they’re vowels or consonants:
//: c03:VowelsAndConsonants.java
// Demonstrates the switch statement.
import com.bruceeckel.simpletest.*;
public class VowelsAndConsonants {
static Test monitor = new Test();
public static void main(String[] args) {
for(int i = 0; i < 100; i++) {
char c = (char)(Math.random() * 26 + 'a');
System.out.print(c + ": ");
switch(c) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u': System.out.println("vowel");
break;
case 'y':
case 'w': System.out.println("Sometimes a vowel");
break;
default: System.out.println("consonant");
}
monitor.expect(new String[] {
"%% [aeiou]: vowel|[yw]: Sometimes a vowel|" +
"[^aeiouyw]: consonant"
}, Test.AT_LEAST);
}
}
} ///:~
Since Math.random( ) generates a value between 0 and 1, you need only multiply it by the upper bound of the range of numbers you want to produce (26 for the letters in the alphabet) and add an offset to establish the lower bound.
Although it appears you’re switching on a character here, the switch statement is actually using the integral value of the character. The single-quoted characters in the case statements also produce integral values that are used for comparison.
Notice how the cases can be “stacked” on top of each other to provide multiple matches for a particular piece of code. You should also be aware that it’s essential to put the break statement at the end of a particular case; otherwise, control will simply drop through and continue processing on the next case.
In the regular expression in this expect( ) statement, the ‘|’ is used to indicate three different possibilities. The ‘[]’ encloses a “set” of characters in a regular expression, so the first part says “one of a, e, i, o, or u, followed by a colon and the word ‘vowel’.” The second possibility indicates either y or w and: “Sometimes a vowel.” The set in the third possibility begins with a ‘^’, which means “not any of the characters in this set,” so it indicates anything other than a vowel will match.
Calculation details
The statement:
char c = (char)(Math.random() * 26 + 'a');
deserves a closer look. Math.random( ) produces a double, so the value 26 is converted to a double to perform the multiplication, which also produces a double. This means that ‘a’ must be converted to a double to perform the addition. The double result is turned back into a char with a cast.
What does the cast to char do? That is, if you have the value 29.7 and you cast it to a char, is the resulting value 30 or 29? The answer to this can be seen in this example:
//: c03:CastingNumbers.java
// What happens when you cast a float
// or double to an integral value?
import com.bruceeckel.simpletest.*;
public class CastingNumbers {
static Test monitor = new Test();
public static void main(String[] args) {
double
above = 0.7,
below = 0.4;
System.out.println("above: " + above);
System.out.println("below: " + below);
System.out.println("(int)above: " + (int)above);
System.out.println("(int)below: " + (int)below);
System.out.println("(char)('a' + above): " +
(char)('a' + above));
System.out.println("(char)('a' + below): " +
(char)('a' + below));
monitor.expect(new String[] {
"above: 0.7",
"below: 0.4",
"(int)above: 0",
"(int)below: 0",
"(char)('a' + above): a",
"(char)('a' + below): a"
});
}
} ///:~
So the answer is that casting from a float or double to an integral value always truncates the number.
A second question concerns Math.random( ). Does it produce a value from zero to one, inclusive or exclusive of the value ‘1’? In math lingo, is it (0,1), or [0,1], or (0,1] or [0,1)? (The square bracket means “includes,” whereas the parenthesis means “doesn’t include.”) Again, a test program might provide the answer:
//: c03:RandomBounds.java
// Does Math.random() produce 0.0 and 1.0?
// {RunByHand}
public class RandomBounds {
static void usage() {
System.out.println("Usage: \n\t" +
"RandomBounds lower\n\tRandomBounds upper");
System.exit(1);
}
public static void main(String[] args) {
if(args.length != 1) usage();
if(args[0].equals("lower")) {
while(Math.random() != 0.0)
; // Keep trying
System.out.println("Produced 0.0!");
}
else if(args[0].equals("upper")) {
while(Math.random() != 1.0)
; // Keep trying
System.out.println("Produced 1.0!");
}
else
usage();
}
} ///:~
To run the program, you type a command line of either:
java RandomBounds lower
or
java RandomBounds upper
In both cases you are forced to break out of the program manually, so it would appear that Math.random( ) never produces either 0.0 or 1.0. But this is where such an experiment can be deceiving. If you consider[18] that there are about 262 different double fractions between 0 and 1, the likelihood of reaching any one value experimentally might exceed the lifetime of one computer, or even one experimenter. It turns out that 0.0 is included in the output of Math.random( ). Or, in math lingo, it is [0,1).