switch Multiple-Selection Statement
We discussed the if single-selection statement and the if...else double-selectionstatement in Chapter 4. Java provides the switch multiple-selection statement to perform different actions based on the possible values of an integer variable or expression. Each action. is associated with the value of a constant integral expression (i.e., a constant value of type byte, short, int or char, but not long) that the variable or expression on which the switch is based may assume.
GradeBook Class with switch Statement to Count A, B, C, D and F Grades
Figure 5.9 contains an enhanced version of the GradeBook class introduced in Chapter 3 and further developed in Chapter 4. The version of the class we now present not only calculates the average of a set of numeric grades entered by the user, but uses a switch statement to determine whether each grade is the equivalent of an A, B, C, D or F and to increment the appropriate grade counter. The class also displays a summary of the number of students who received each grade. Please refer to Fig. 5.10 for sample input and output of the GradeBook-Test application that uses class GradeBook to process a set of grades.
Figure 5.9. GradeBook class uses switch statement to count A, B, C, D and F grades.
(This item is displayed on pages 193 - 195 in the print version)
1 // Fig. 5.9: GradeBook.java 2 // GradeBook class uses switch statement to count A, B, C, D and F grades. 3 import java.util.Scanner; // program uses class Scanner 4 5 public class GradeBook 6 { 7 private String courseName; // name of course this GradeBook represents 8 private int total; // sum of grades 9 private int gradeCounter; // number of grades entered 10 private int aCount; // count of A grades 11 private int bCount; // count of B grades 12 private int cCount; // count of C grades 13 private int dCount; // count of D grades 14 private int fCount; // count of F grades 15 16 // constructor initializes courseName; 17 // int instance variables are initialized to 0 by default 18 public GradeBook( String name ) 19 { 20 courseName = name; // initializes courseName 21 } // end constructor 22 23 // method to set the course name 24 public void setCourseName( String name ) 25 { 26 courseName = name; // store the course name 27 } // end method setCourseName 28 29 // method to retrieve the course name 30 public String getCourseName() 31 { 32 return courseName; 33 } // end method getCourseName 34 35 // display a welcome message to the GradeBook user 36 public void displayMessage() 37 { 38 // getCourseName gets the name of the course 39 System.out.printf( "Welcome to the grade book for %s! ", 40 getCourseName() ); 41 } // end method displayMessage 42 43 // input arbitrary number of grades from user 44 public void inputGrades() 45 { 46 Scanner input = new Scanner( System.in ); 47 48 int grade; // grade entered by user 49 50 System.out.printf( "%s %s %s %s ", 51 "Enter the integer grades in the range 0-100.", 52 "Type the end-of-file indicator to terminate input:", 53 "On UNIX/Linux/Mac OS X type d then press Enter", 54 "On Windows type z then press Enter" ); 55 56 // loop until user enters the end-of-file indicator 57 while ( input.hasNext() ) 58 { 59 grade = input.nextInt(); // read grade 60 total += grade; // add grade to total 61 ++gradeCounter; // increment number of grades 62 63 // call method to increment appropriate counter 64 incrementLetterGradeCounter( grade ); 65 } // end while 66 } // end method inputGrades 67 68 // add 1 to appropriate counter for specified grade 69 public void incrementLetterGradeCounter( int numericGrade ) 70 { 71 // determine which grade was entered 72 switch ( grade / 10 ) 73 { 74 case 9: // grade was between 90 75 case 10: // and 100 76 ++aCount; // increment aCount 77 break; // necessary to exit switch 78 79 case 8: // grade was between 80 and 89 80 ++bCount; // increment bCount 81 break; // exit switch 82 83 case 7: // grade was between 70 and 79 84 ++cCount; // increment cCount 85 break; // exit switch 86 87 case 6: // grade was between 60 and 69 88 ++dCount; // increment dCount 89 break; // exit switch 90 91 default: // grade was less than 60 92 ++fCount; // increment fCount 93 break; // optional; will exit switch anyway 94 } // end switch 95 } // end method incrementLetterGradeCounter 96 97 // display a report based on the grades entered by user 98 public void displayGradeReport() 99 { 100 System.out.println( " Grade Report:" ); 101 102 // if user entered at least one grade... 103 if ( gradeCounter != 0 ) 104 { 105 // calculate average of all grades entered 106 double average = (double) total / gradeCounter; 107 108 // output summary of results 109 System.out.printf( "Total of the %d grades entered is %d ", 110 gradeCounter, total ); 111 System.out.printf( "Class average is %.2f ", average ); 112 System.out.printf( "%s %s%d %s%d %s%d %s%d %s%d ", 113 "Number of students who received each grade:", 114 "A: ", aCount, // display number of A grades 115 "B: ", bCount, // display number of B grades 116 "C: ", cCount, // display number of C grades 117 "D: ", dCount, // display number of D grades 118 "F: ", fCount ); // display number of F grades 119 } // end if 120 else // no grades were entered, so output appropriate message 121 System.out.println( "No grades were entered" ); 122 } // end method displayGradeReport 123 } // end class GradeBook |
Figure 5.10. GradeBookTest creates a GradeBook object and invokes its methods.
(This item is displayed on page 198 in the print version)
1 // Fig. 5.10: GradeBookTest.java 2 // Create GradeBook object, input grades and display grade report. 3 4 public class GradeBookTest 5 { 6 public static void main( String args[] ) 7 { 8 // create GradeBook object myGradeBook and 9 // pass course name to constructor 10 GradeBook myGradeBook = new GradeBook( 11 "CS101 Introduction to Java Programming" ); 12 13 myGradeBook.displayMessage(); // display welcome message 14 myGradeBook.inputGrades(); // read grades from user 15 myGradeBook.displayGradeReport(); // display report based on grades 16 } // end main 17 } // end class GradeBookTest
|
Like earlier versions of the class, class GradeBook (Fig. 5.9) declares instance variable courseName (line 7) and contains methods setCourseName (lines 2427), getCourseName (lines 3033) and displayMessage (lines 3641), which set the course name, store the course name and display a welcome message to the user, respectively. The class also contains a constructor (lines 1821) that initializes the course name.
Class GradeBook also declares instance variables total (line 8) and gradeCounter (line 9), which keep track of the sum of the grades entered by the user and the number of grades entered, respectively. Lines 1014 declare counter variables for each grade category. Class GradeBook maintains total, gradeCounter and the five letter-grade counters as instance variables so that these variables can be used or modified in any of the class's methods. Note that the class's constructor (lines 1821) sets only the course name, because the remaining seven instance variables are ints and are initialized to 0 by default.
Class GradeBook (Fig. 5.9) contains three additional methodsinputGrades, incrementLetterGradeCounter and displayGradeReport. Method inputGrades (lines 4466) reads an arbitrary number of integer grades from the user using sentinel-controlled repetition and updates instance variables total and gradeCounter. Method inputGrades calls method incrementLetterGradeCounter (lines 6995) to update the appropriate letter-grade counter for each grade entered. Class GradeBook also contains method displayGradeReport (lines 98122), which outputs a report containing the total of all grades entered, the average of the grades and the number of students who received each letter grade. Let's examine these methods in more detail.
Line 48 in method inputGrades declares variable grade, which will store the user's input. Lines 5054 prompt the user to enter integer grades and to type the end-of-file indicator to terminate the input. The end-of-file indicator is a system-dependent keystroke combination which the user enters to indicate that there is no more data to input. In Chapter 14, Files and Streams, we will see how the end-of-file indicator is used when a program reads its input from a file.
On UNIX/Linux/Mac OS X systems, end-of-file is entered by typing the sequence
d
on a line by itself. This notation means to simultaneously press both the ctrl key and the d key. On Windows systems, end-of-file can be entered by typing
z
[Note: On some systems, you must press Enter after typing the end-of-file key sequence. Also, Windows typically displays the characters ^Z on the screen when the end-of-file indicator is typed, as is shown in the output of Fig. 5.9]
Portability Tip 5.1
The keystroke combinations for entering end-of-file are system dependent. |
The while statement (lines 5765) obtains the user input. The condition at line 57 calls Scanner method hasNext to determine whether there is more data to input. This method returns the boolean value TRue if there is more data; otherwise, it returns false. The returned value is then used as the condition in the while statement. As long as the end-of-file indicator has not been typed, method hasNext will return TRue.
Line 59 inputs a grade value from the user. Line 60 uses the += operator to add grade to total. Line 61 increments gradeCounter. The class's displayGradeReport method uses these variables to compute the average of the grades. Line 64 calls the class's incrementLetterGradeCounter method (declared in lines 6995) to increment the appropriate letter-grade counter based on the numeric grade entered.
Method incrementLetterGradeCounter contains a switch statement (lines 7294) that determines which counter to increment. In this example, we assume that the user enters a valid grade in the range 0100. A grade in the range 90100 represents A, 8089 represents B, 7079 represents C, 6069 represents D and 059 represents F. The switch statement consists of a block that contains a sequence of case labels and an optional default case. These are used in this example to determine which counter to increment based on the grade.
When the flow of control reaches the switch, the program evaluates the expression in the parentheses (grade / 10) following keyword switch. This is called the controlling expression of the switch. The program compares the value of the controlling expression (which must evaluate to an integral value of type byte, char, short or int) with each case label. The controlling expression in line 72 performs integer division, which truncates the fractional part of the result. Thus, when we divide any value for 0100 by 10, the result is always a value from 0 to 10.We use several of these values in our case labels. For example, if the user enters the integer 85, the controlling expression evaluates to the int value 8. The switch compares 8 with each case. If a match occurs (case 8: at line 79), the program executes the statements for that case. For the integer 8, line 80 increments bCount, because a grade in the 80s is a B. The break statement (line 81) causes program control to proceed with the first statement after the switchin this program, we reach the end of method incrementLetterGradeCounter's body, so control returns to line 65 in method inputGrades (the first line after the call to incrementLetterGradeCounter). This line marks the end of the body of the while loop that inputs grades (lines 5765), so control flows to the while's condition (line 57) to determine whether the loop should continue executing.
The cases in our switch explicitly test for the values 10, 9, 8, 7 and 6. Note the cases at lines 7475 that test for the values 9 and 10 (both of which represent the grade A). Listing cases consecutively in this manner with no statements between them enables the cases to perform the same set of statementswhen the controlling expression evaluates to 9 or 10, the statements in lines 7677 will execute. The switch statement does not provide a mechanism for testing ranges of values, so every value that must be tested should be listed in a separate case label. Note that each case can have multiple statements. The switch statement differs from other control statements in that it does not require braces around multiple statements in each case.
Without break statements, each time a match occurs in the switch, the statements for that case and subsequent cases execute until a break statement or the end of the switch is encountered. This is often referred to as "falling through" to the statements in subsequent cases. (This feature is perfect for writing a concise program that displays the iterative song "The Twelve Days of Christmas" in Exercise 5.29.)
Common Programming Error 5.7
Forgetting a break statement when one is needed in a switch is a logic error. |
If no match occurs between the controlling expression's value and a case label, the default case (lines 9193) executes. We use the default case in this example to process all controlling-expression values that are less than 6, that is, all failing grades. If no match occurs and the switch does not contain a default case, program control simply continues with the first statement after the switch.
GradeBookTest Class that Demonstrates Class GradeBook
Class GradeBookTest (Fig. 5.10) creates a GradeBook object (lines 1011). Line 13 invokes the object's displayMessage method to output a welcome message to the user. Line 14 invokes the object's inputGrades method to read a set of grades from the user and keep track of the sum of all the grades entered and the number of grades. Recall that method inputGrades also calls method incrementLetterGradeCounter to keep track of the number of students who received each letter grade. Line 15 invokes method displayGradeReport of class GradeBook, which outputs a report based on the grades entered (as in the input/output window in Fig. 5.10). Line 103 of class GradeBook (Fig. 5.9) determines whether the user entered at least one gradethis helps us avoid dividing by zero. If so, line 106 calculates the average of the grades. Lines 109118 then output the total of all the grades, the class average and the number of students who received each letter grade. If no grades were entered, line 121 outputs an appropriate message. The output in Fig. 5.10 shows a sample grade report based on 10 grades.
Note that class GradeBookTest (Fig. 5.10) does not directly call GradeBook method incrementLetterGradeCounter (lines 6995 of Fig. 5.9). This method is used exclusively by method inputGrades of class GradeBook to update the appropriate letter-grade counter as each new grade is entered by the user. Method incrementLetterGradeCounter exists solely to support the operations of class GradeBook's other methods and thus could be declared private. Recall from Chapter 3 that methods declared with access modifier private can be called only by other methods of the class in which the private methods are declared. Such methods are commonly referred to as utility methods or helper methods because they can be called only by other methods of that class and are used to support the operation of those methods.
switch Statement UML Activity Diagram
Figure 5.11 shows the UML activity diagram for the general switch statement. Most switch statements use a break in each case to terminate the switch statement after processing the case. Figure 5.11 emphasizes this by including break statements in the activity diagram. The diagram makes it clear that the break statement at the end of a case causes control to exit the switch statement immediately.
Figure 5.11. switch multiple-selection statement UML activity diagram with break statements.
The break statement is not required for the switch's last case (or the default case, when it appears last), because execution continues with the next statement after the switch.
Software Engineering Observation 5.2
Provide a default case in switch statements. Including a default case focuses you on the need to process exceptional conditions. |
Good Programming Practice 5.8
Although each case and the default case in a switch can occur in any order, place the default case last. When the default case is listed last, the break for that case is not required. Some programmers include this break for clarity and symmetry with other cases. |
When using the switch statement, remember that the expression after each case can be only a constant integral expressionthat is, any combination of integer constants that evaluates to a constant integer value (e.g., -7, 0 or 221). An integer constant is simply an integer value. In addition, you can use character constantsspecific characters in single quotes, such as 'A', '7' or '$'which represent the integer values of characters. (Appendix B, ASCII Character Set shows the integer values of the characters in the ASCII character set, which is a subset of the Unicode character set used by Java.)
The expression in each case also can be a constant variablea variable that contains a value which does not change for the entire program. Such a variable is declared with keyword final (discussed in Chapter 6, Methods: A Deeper Look). J2SE 5.0 has a new feature called enumerations, which we also present in Chapter 6. Enumeration constants can also be used in case labels. In Chapter 10, Object-Oriented Programming: Polymorphism, we present a more elegant way to implement switch logicwe use a technique called polymorphism to create programs that are often clearer, easier to maintain and easier to extend than programs using switch logic.