Java Reference
In-Depth Information
Solution 23: No Pain, No Gain
At first glance, this program might appear to print out the words Pain , Gain , and Main with equal
likelihood, varying from run to run. It appears to choose the first letter of the word, depending on
the value chosen by the random number generator: M for 0, P for 1, and G for 2. The puzzle's title
might have provided you with a clue that it doesn't actually print Pain or Gain . Perhaps more
surprisingly, it doesn't print Main either, and its behavior doesn't vary from run to run. It always
prints ain .
Three bugs conspire to cause this behavior. Did you spot them all? The first bug is that the random
number is chosen so the switch statement can reach only two of its three cases. The specification
for Random.nextInt(int) says: "Returns a pseudorandom, uniformly distributed int value between
0 (inclusive) and the specified value (exclusive)" [Java-API] . This means that the only possible
values of the expression rnd.nextInt(2) are 0 and 1 . The switch statement will never branch to
case 2 , which suggests that the program will never print Gain . The parameter to nextInt should
have been 3 rather than 2 .
This is a fairly common source of problems, known as a fencepost error . The name comes from the
common but incorrect answer of 10 to the question, If you build a fence 100 feet long with posts 10
feet apart, how many posts do you need? Both 11 and 9 are correct answers, depending on whether
there are posts at the ends of the fence, but 10 is wrong. Watch out for fencepost errors.
Whenever you are working with lengths, ranges, or moduli, be careful to determine which
endpoints should be included, and make sure that your code behaves accordingly.
The second bug is that there are no break statements between the cases. Whatever the value of the
switch expression, the program will execute that case and all subsequent cases [JLS 14.11]. Each
case assigns a value to the variable word , and the last assignment wins. The last assignment will
always be the one in the final case ( default ), which is new StringBuffer('M') . This suggests that
the program will never print Pain or Gain but always Main .
The absence of break statements in switch cases is a common error that tools can help you catch.
As of release 5.0, javac provides the -Xlint:fallthrough flag to generate warnings when you
forget a break between one case and the next. Don't fall through from one nonempty case to
another. It's bad style because it's unusual and therefore confusing to the reader. Nine times out of
ten, it indicates an error. If Java had not been modeled after C , its switch statement would probably
not require breaks. The lesson for language designers is to consider providing a structured switch
statement.
 
 
Search WWH ::




Custom Search