Chapter 6

Pulling a Switcheroo

IN THIS CHAPTER

check Avoiding the trouble with big else-if statements

check Using the switch statement

check Creating case groups

check Using characters with case

In Book 2, Chapter 4, you find out about the workhorses of Java decision-making: boolean expressions and the mighty if statement. In this chapter, you discover another Java tool for decision-making: the switch statement. The switch statement is a pretty limited beast, but it excels at making one particular type of decision: choosing one of several actions based on a value stored in an integer variable. As it turns out, the need to do just that comes up a lot. You want to keep the switch statement handy for use when such a need arises.

Battling else-if Monstrosities

Many applications call for a simple logical selection of things to be done depending on some value that controls everything. As I describe in Book 2, Chapter 4, such things are usually handled with big chains of else-if statements all strung together.

Unfortunately, these things can quickly get out of hand. else-if chains can end up looking like DNA double-helix structures or those things that dribble down from the tops of the computer screens in The Matrix, with hundreds of lines of code that string else-if after else-if. The switch statement provides a much more concise alternative.

Viewing an example else-if program

Listing 6-1 shows a bit of a program that might be used to decode error codes in a Florida or Ohio voting machine.

LISTING 6-1 The else-if Version of a Voting Machine Error Decoder

import java.util.Scanner;
public class VoterApp
{
static Scanner sc = new Scanner(System.in);
public static void main(String[] args)
{
System.out.println
("Welcome to the voting machine "
+ "error code decoder. "
+ "If your voting machine generates "
+ "an error code, "
+ "you can use this program to determine "
+ "the exact cause of the error. ");
System.out.print("Enter the error code: ");

int err = sc.nextInt();

String msg;
if (err==1)
msg = "Voter marked more than one candidate. "
+ "Ballot rejected.";
else if (err==2)
msg = "Box checked and write-in candidate "
+ "entered. Ballot rejected.";
else if (err==3)
msg = "Entire ballot was blank. "
+ "Ballot filled in according to "
+ "secret plan.";
else if (err==4)
msg = "Nothing unusual about the ballot. "
+ "Voter randomly selected for tax audit.";
else if (err==5)
msg = "Voter filled in every box. "
+ "Ballot counted twice.";
else if (err==6)
msg = "Voter drooled in voting machine. "
+ "Beginning spin cycle.";
else if (err==7)
msg = "Voter lied to pollster after voting. "
+ "Voter's ballot changed "
+ "to match polling data.";
else
msg = "Voter filled out ballot correctly. "
+ "Ballot discarded anyway.";
System.out.println(msg);
}
}

Wow! And this program has to decipher just 7 error codes. What if the machine had 500 codes?

Creating a better version of the example program

Fortunately, Java has a special statement that’s designed just for the kind of task represented by the voting machine error decoder program: the switch statement. Specifically, the switch statement is useful when you need to select one of several alternatives based on the value of an integer or character type variable.

Listing 6-2 shows a version of the voting machine error decoder program that uses a switch statement instead of a big else-if structure. I think you’ll agree that this version of the program is a bit easier to follow. The switch statement makes it clear that all the messages are selected based on the value of the err variable.

LISTING 6-2 The switch Version of the Voting Machine Error Decoder

import java.util.Scanner;
public class VoterApp2
{
static Scanner sc = new Scanner(System.in);

public static void main(String[] args)
{
System.out.println
("Welcome to the voting machine "
+ "error code decoder. "
+ "If your voting machine generates "
+ "an error code, "
+ "you can use this program to determine "
+ "the exact cause of the error. ");
System.out.print("Enter the error code: ");
int err = sc.nextInt();

String msg;

switch (err)
{
case 1:
msg = "Voter marked more than one "
+ "candidate. Ballot rejected.";
break;
case 2:
msg = "Box checked and write-in candidate "
+ "entered. Ballot rejected.";
break;
case 3:
msg = "Entire ballot was blank. "
+ "Ballot filled in according to "
+ "secret plan.";
break;
case 4:
msg = "Nothing unusual about the ballot. "
+ "Voter randomly selected for tax audit.";
break;
case 5:
msg = "Voter filled in every box. "
+ "Ballot counted twice.";
break;
case 6:
msg = "Voter drooled in voting machine. "
+ "Beginning spin cycle.";
break;
case 7:
msg = "Voter lied to pollster after voting. "
+ "Voter's ballot changed "
+ "to match polling data.";
break;
default:
msg = "Voter filled out ballot correctly. "
+ "Ballot discarded anyway.";
break;
}
System.out.println(msg);
}
}

Using the switch Statement

The basic form of the switch statement is this:

switch (expression)
{
case constant:
statements;
break;
[ case constant-2:
statements;
break; ]…
[ default:
statements;
break; ]…
}

The expression must evaluate to an int, short, byte, or char. It can’t be a long or a floating-point type.

You can code as many case groups as you want or need. Each group begins with the word case, followed by a constant (usually, a simple numeric literal) and a colon. Then you code one or more statements that you want executed if the value of the switch expression equals the constant. The last line of each case group is a break statement, which causes the entire switch statement to end.

The default group, which is optional, is like a catch-all case group. Its statements are executed only if none of the previous case constants match the switch expression.

tip Note that the case groups are not true blocks marked with braces. Instead, each case group begins with the case keyword and ends with the case keyword that starts the next case group. All the case groups together, however, are defined as a block marked with a set of braces.

warning The last statement in each case group usually is a break statement. A break statement causes control to skip to the end of the switch statement. If you omit the break statement, control falls through to the next case group. Accidentally leaving out break statements is the most common cause of trouble with the switch statement.

Viewing a boring switch example, complete with flowchart

Okay, the voting machine error decoder was kind of fun. Here’s a more down-to-earth example. Suppose that you need to set a commission rate based on a sales class represented by an integer (1, 2, or 3) according to this table:

Class

Commission Rate

1

2%

2

3.5%

3

5%

Any other value

0%

You could do this with the following switch statement:

double commissionRate;
switch (salesClass)
{
case 1:
commissionRate = 0.02;
break;
case 2:
commissionRate = 0.035;
break;
case 3:
commissionRate = 0.05;
break;
default:
commissionRate = 0.0;
break;
}

Figure 6-1 shows a flowchart that describes the operation of this switch statement. As you can see, this flowchart is similar to the flowchart in Figure 4-3 (Book 2, Chapter 4), because the operation of the switch statement is similar to the operation of a series of else-if statements.

image

FIGURE 6-1: The flowchart for a switch statement.

tip Flowcharts remind me of the good old days, when many COBOL programming shops required their programmers to draw flowcharts for every program they wrote before they were allowed to write any code. The flowcharts didn’t really help programmers write better programs, but they were fun to draw.

Putting if statements inside switch statements

You’re free to include any type of statements you want in the case groups, including if statements. Suppose that your commission structure depends on total sales as well as sales class, as in this table:

Class

Sales < $10,000

Sales $10,000 and Above

1

1%

2%

2

2.5%

3.5%

3

4%

5%

Any other value

0%

0%

You can use the following switch statement:

double commissionRate;
switch (salesClass)
{
case 1:
if (salesTotal < 10000.0)
commissionRate = 0.01;
else
commissionRate = 0.02;
break;
case 2:
if (salesTotal < 10000.0)
commissionRate = 0.025;
else
commissionRate = 0.035;
break;
case 3:
if (salesTotal < 10000.0)
commissionRate = 0.04;
else
commissionRate = 0.05;
break;
default:
commissionRate = 0.0;
break;
}

Here each case group includes an if statement. If necessary, these if statements could be complex nested if statements.

Other than the if statements within the case groups, there’s nothing here to see, folks. Move along.

Creating Character Cases

Aside from having a nice alliterative title, this section shows how you can use a char variable rather than an integer in a switch statement. When you use a char type, providing two consecutive case constants for each case group is common, to allow for both lowercase and uppercase letters. Suppose that you need to set the commission rates for the sales class based on character codes rather than on integer values, according to this table:

Class

Commission Rate

A or a

2%

B or b

3.5%

C or c

5%

Any other value

0%

Here’s a switch statement that can do the trick:

double commissionRate;
switch (salesClass)
{
case 'A':
case 'a':
commissionRate = 0.02;
break;
case 'B':
case 'b':
commissionRate = 0.035;
break;
case 'C':
case 'c':
commissionRate = 0.05;
break;
default:
commissionRate = 0.0;
break;
}

The key to understanding this example is realizing that you don’t have to code any statements at all for a case group — and that if you omit the break statement from a case group, control falls through to the next case group. Thus the case 'A' group doesn’t contain any statements, but control falls through to the case 'a' group.

remember You use apostrophes, not quotation marks, to create character literals.

Intentionally Leaving Out a Break Statement

Although the most common cause of problems with the switch statement is accidentally leaving out a break statement at the end of a case group, sometimes you need to do it on purpose. Many applications have features that are progressively added based on a control variable. Your local car wash, for example, may sell several packages with different services, as in this table:

Package

Services

A

Wash, vacuum, and hand-dry

B

Package A + wax

C

Package B + leather/vinyl treatment

D

Package C + tire treatment

E

Package D + new-car scent

Listing 6-3 shows an application that displays all the products you get when you order a specific package. It works by testing the package codes in a switch statement in reverse order (starting with package E) and adding the products that come with each package to the details variable. None of the case groups except the last includes a break statement. As a result, control falls through each case group to the next group. Thus, once a case group has tested true, the rest of the case groups in the switch statement are executed.

LISTING 6-3 The Car Wash Application

import java.util.Scanner;

public class CarWashApp
{
static Scanner sc = new Scanner(System.in);

public static void main(String[] args)
{
System.out.println
("The car wash application! ");
System.out.print("Enter the package code: ");
String s = sc.next();
char p = s.charAt(0);

String details = "";

switch (p)
{
case 'E':
case 'e':
details += " New Car Scent, plus … ";
case 'D':
case 'd':
details += " Tire Treatment, plus … ";
case 'C':
case 'c':
details +=
" Leather/Vinyl Treatment, plus … ";
case 'B':
case 'b':
details += " Wax, plus … ";
case 'A':
case 'a':
details += " Wash, vacuum, and hand dry. ";
break;
default:
details = "That's not one of the codes.";
break;
}
System.out.println(" That package includes: ");
System.out.println(details);
}
}

tip Just between you and me, writing programs that depend on switch statements falling through the cracks (as in this example) isn’t really a good idea. Instead, consider placing the statements for each case group in separate methods and then calling all the methods you need for each case group. Then you can use a break statement at the end of each group to prevent falling through. Listing 6-4 shows a version of the car wash application that uses this technique to prevent fall-throughs in the switch statement. (Using simple fall-throughs to treat uppercase and lowercase characters the same way isn’t as confusing, so this program still uses that technique.)

LISTING 6-4 A Version of the Car Wash Program That Prevents Nasty Falls

import java.util.Scanner;

public class CarWashApp2
{
static Scanner sc = new Scanner(System.in);
public static void main(String[] args)
{
System.out.println
("The car wash application! ");
System.out.print("Enter the package code: ");
String s = sc.next();
char p = s.charAt(0);

String details = "";
switch (p)
{
case 'E':
case 'e':
details = packageE() + packageD() + packageC()
+ packageB() + packageA();
break;
case 'D':
case 'd':
details = packageD() + packageC()
+ packageB() + packageA();
break;
case 'C':
case 'c':
details = packageC() + packageB()
+ packageA();
break;
case 'B':
case 'b':
details = packageB() + packageA();
break;
case 'A':
case 'a':
details = packageA();
break;
default:
details = "That's not one of the codes.";
break;
}
System.out.println(" That package includes: ");
System.out.println(details);
}

public static String packageA()
{
return " Wash, vacuum, and hand dry. ";
}

public static String packageB()
{
return " Wax, plus … ";
}

public static String packageC()
{
return " Leather/Vinyl Treatment, plus … ";
}

public static String packageD()
{
return " Tire Treatment, plus … ";
}

public static String packageE()
{
return " New Car Scent, plus … ";
}
}

Switching with Strings

Beginning with Java 1.7, the expression in the switch statement can evaluate to a String value. Listing 6-5 shows a version of the car wash program that uses the string codes PRESIDENTIAL, ELITE, DELUXE, SUPER, and STANDARD as the car wash types, instead of the letters A through E. Notice that to allow for variations in how a user might capitalize these codes, the user’s input is converted to all capital letters before it is tested against the string constants in the switch statement.

LISTING 6-5 A Version of the Car Wash Program That Uses a String

import java.util.Scanner;

public class CarWashStringApp
{
static Scanner sc = new Scanner(System.in);

public static void main(String[] args)
{
System.out.println("The car wash application ");
System.out.print("Enter the package code: ");
String s = sc.next();

String details = "";

switch (s.toUpperCase())
{
case "PRESIDENTIAL":
details += " New Car Scent, plus … ";
case "ELITE":
details += " Tire Treatment, plus … ";
case "DELUXE":
details += " Leather/Vinyl Treatment, plus … ";
case "SUPER":
details += " Wax, plus … ";
case "STANDARD":
details += " Wash, vacuum, and hand dry. ";
break;
default:
details = "That's not one of the codes.";
break;
}
System.out.println(" That package includes: ");
System.out.println(details);
}
}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset