INTRODUCTION TO PROGRAMMING IN JAVA: SELECTION (SWITCH)

NOTE: This set of www pages is not the set of www pages for the curent version of COMP101. The pages are from a previous version that, at the request of students, I have kept on line.


CONTENTS

1. Overview
2. Java "switch" statements
3. Example problem - simple calculator
3.1. Requirements
3.2. Analysis
 
3.3. Design
3.4. Implementation
3.5. Testing
4.Further example illustrating the use of the Java "switch" statement

Notes: (i) Includes further examples of use of expressions, casts, reading single characters from input stream and "if-else". (ii) Where we read from the input stream this is handled somewhat clumsily, it would be better to read in the input as a single string and then use methods from the StringTokernizer class to obtain the components; however we will not be covering this class in this sequence of WWW pages. (iii) The problem example also makes use of the divide by zero error check method described on the previous WWW page.




1. OVERVIEW

An "if-else" statement supports selection from only two alternatives; we can of course nest such statements or use constructs such as "if ... else if ... else", but it is usually more succinct to use a switch statement (also sometimes referred to as a case statement). Switch statement allows selection from many alternatives where each alternative is linked to a predicate, referred to as a selector, which when evaluated to true causes an associated program statement (or statements) to be executed.



2. JAVA SWITCH STATEMENT

In Java the general format of a switch (case) statement is as follows:

switch SELECTOR {
    case < SELECTOR_VALUE_1 > : 
	< STATEMENTS_1 >
	break
        ...
    case < SELECTOR_VALUE_N > : 
	< STATEMENTS_N >
	break	
    default:
        < DEFAULT_STATEMENTS >
    }

Selections may be made according to:

  1. A distinct value of a given selector, or
  2. A default value.

Selectors must be of a discrete type (such as an integer or a character). An example Java class containing a switch statement is given in Table 1.

 

Where N is of type integer, the code in Table 1 states that:

When the value of N is equal to 0 output "N equals 0".
When the value of N is equal to 1 output "N equals 1 or 5".
When the value of N is within the range 2 to 4 inclusive output "N equals 2, 3 or 4".
Otherwise by default output "N less than 0 or greater than 4".

Note the use of the break statement in the code. Note also that it is consider good practise to always include a default alternative to act as a "catch all".

// SWITCH EXAMPLE APPLICATION
// Frans Coenen
// The University of Liverpool, UK
// Wednesday 24 March 1999
// Revised Monday 25 July 2005 
      
import java.util.*; 

class SwitchExampleApp {

    // ---------------- FIELDS ------------------ 
        
    // Create Scanner class instance	
    private static Scanner input = new Scanner(System.in);
    
    // --------------- METHODS ------------------

    /** MAIN METHOD: */
    
    public static void main(String[] args) {
        // input
        System.out.print("Input an integer ");
        int number = input.nextInt(); 
    
        // Process number using a case statement
        switch (number) {
            case 0:
    	        System.out.println("Number is 0");
	        break;
            case 1:
    	        System.out.println("Number is 1");
	        break;
            case 2:
            case 3:
            case 4:
    	    	System.out.println("Number is 2, 3 or 4");
	    	break;
            default:
   		System.out.println("Number is less than 0 or greater than 4");
	    }
   	}
    }

Table 1: Switch example program



3. EXAMPLE PROBLEM - SIMPLE CALCULATOR


3.1. Requirements

Design and develop a simple calculator Java program. The calculator (Figure 1) should be able to resolve simple arithmetic expressions of the form:

< OPERAND > < OPERATOR > < OPERAND >
SIMPLE CALCULATOR

Figure 1: Simple calculator

Where < OPERAND > is an integer of some kind and < OPERATOR > is one of the operators `+', `-', `*' or `/' (integer division). Thus given the expression:

63*35

The program should calculate the value of the expression and display the result.

Note: remember to include a divide by zero test.


3.2 Analysis

A class diagram for the proposed solution is given in Figure 2.


3.3 Design

The default Java integer range is -2147483648..2147483647. Thus the highest value that we can compute is the result of x*x which must be less than 2147483647. We can calculate the maximum permitable value of x as follows:

CALCULATOR CLASS DIAGRAM

Figure 2: Calculator class diagram

x = sqrt(2147483647) = 46340.95000105

Thus, rounding down (casting) to the nearest integer, the maximum value for x is 46340. We can check this:

46340*46340=2147395600

which is less than the 2147483647 prescribed maximum for the int range, and

46341*46341=2147488281

which is greater than the 2147483647 maximum for the int range and will thus result in an integer overflow error in the context of the proposed simple calculator. The minimum value for x is then -46340 (-46340*46340=-2147395600 which is greater than the -2147483648 prescribed minimum for the int range). We will therefore insist that the input values for the operands are within the range of -46340..46340 inclusive.

From Figure 2 we require two class, Calculator and CalculatorApp. The Calculatorclass definition contains fields for not only the operands and operator, but also two constants to hold the maximum and minimum permitted values for the operands.

Note 1: In actual fact the result of 46341x46341 will be -2147479015 because the "sign bit" will get set causing the result to be interpreted as a negative number.


3.3.1 Calculator Class

Field Summary
private char operator
           An instance field in which to store the infix binary operator for a simple sum.
private int operand1
           An instance field in which to store prefix operand for a simple sum.
private int operand2
           An instance field in which to store the postfix operand for a simple sum.
private static int MAXIMUM
           Class constant representing the maximum value for an operand.
private static int MINIMUM
           Class constant representing the minimum value for an operand.

Constructor Summary
Calculator(int newOperand1, char newOperator, int newOpernd2)
           Constructs an instance of the class Calculator given two operands and an operator.

Method Summary
public void makeCalculation()
           Method to carry out the actual calculation. Includes a switch statement to distinguish between the different expected operators ('+', '-', '*' and '/'). In the case of the division operator another instance method is called, division.
private int division()
           Method to test for divide by zero error. If found output error message and return 0. Otherwise carry out division calculation and return result.
public boolean inputCheck()
           Method to check values input for operands using a call to checkOperand. If either operand fails test return false, otherwise return true.
private boolean checkOperand(int operand)
           Method to test if given operand is outside prescribed range identified by constants MAXIMUM and MINIMUM. Returns false if outside range, and true otherwise.

A set of Nassi-Shneiderman charts for the above is given in Figure 3.

NASSI-SHNEIDERMAN CHART FOR CALCULATOR CLASS

Figure 3: Nassi-Shneiderman charts for Calculator class


3.3.1 CalculatorApp Class

Field Summary
private static Scanner input
           A class instance to facilitate input from the input stream.

Method Summary
public static void main(String[] args)
           Main (and only) method in the CalculatorApp class. Takes in two operands and an operator as input and creates an instance of the class Calculator. Then checks that the input is within the prescribed range; if so carries out the required calculation and outputs the result. The dummy data item is only included to make the input more stream line --- the first call to the read() method takes in the operator and stores it in newOp, while the second takes in the carriage return that must follow the operator input.

A Nassi-Shneiderman chart for the above is given below Figure 4. Note how the case statement is included in the chart.

NASSI-SHNEIDERMAN CHART FOR CALCULATOR CLASS

Figure 4: Nassi-Shneiderman chart for CalculatorApp class

The flow of control associated with the solution is indicated by the Activity Diagrams (ADs) given in Figures 5 and 6. There is not an official construct to indicate a case statement in an AD, however, the construct given below adequately allows us to identify the paths through the proposed software.

ACTIVITY DIAGRAM 2

Figure 5: Activity diagram for calculator problem (check input)

ACTIVITY DIAGRAM 1

Figure 6: Activity diagram for calculator problem (switch statement)


3.4. Implementation


3.4.1 Calculator class

// CALCULATOR CLASS
// Frans Coenen
// Tuesday 23 March 1999
// The University of Liverpool, UK   

class Calculator {

    // ------------------- FIELDS ------------------------ 
    
    private char operator;
    private int  operand1, operand2;
    private static final int MAXIMUM = 
    				(int) Math.sqrt((double) Integer.MAX_VALUE);
    private static final int MINIMUM = MAXIMUM*-1;
    
    // ---------------- CONSTRUCTOR ------------------------  
    
    /* Constructor */
    
    public Calculator(int newOperand1, char newOperator, int newOperand2) {
    	operand1 = newOperand1;
	operator = newOperator;
	operand2 = newOperand2;
	}
	
    // ------------------ METHODS ------------------------  
    
    /* Make calculation */
    
    public int makeCalculation() {
    	int answer = 0;		// Default value
	
	// Switch statement 
	
    	switch (operator) {
	    case '+':		// Addition
	    	answer = operand1+operand2;
		break;
	    case '-':		// Subtraction
	    	answer = operand1-operand2;
		break;
	    case '*':		// Multiplication
	    	answer = operand1*operand2;
		break;
	    case '/':		// Division
	    	answer = division();
		break;
	    default:		// Default error case
	    	System.out.println("ERROR 1: Unrecognized operator: " + 
			operator);
	    }
	    
	// Return 	
		
	return(answer);
    	}
	
    /* Division. Test for divide by zero, if OK do calculation and return
    result, otherwise output error message and return 0. */
    
    private int division() {
    	if (operand2 == 0) {
	    System.out.println("ERROR 2: Divide by zero error");
	    return(0);
	    }
	else return(operand1/operand2);
	}
	
     /* Input check, returns true if OK and false otherwise. */
     
     public boolean inputCheck() {
	boolean result = true;
	
	// Check operand 1
	
     	if (!checkOperand(operand1)) result=false;
     	
	// Check operand 2
	
	if (!checkOperand(operand2)) result=false;
	
	// Return
	
	return(result);
	}

    /* Check operand, returns false if outside range and true otherwise
	
    private boolean checkOperand(int operand) {

         // Check operand

         if (operand < MINIMUM || operand > MAXIMUM) {
		System.out.println("Operand, " + operand +
		  	", out of range (" + MINIMUM + ".." + MAXIMUM +
			")");		
		return(false);
		}
	
	// Default return
		
        return(true);
        }
    }

Table 2: Calculator class implementation


3.4.2 CalculatorApp class

// CALCULATOR APPLICATION
// Frans Coenen
// The University of Liverpool, UK  
// Tuesday 23 March 1999
// Revised Monday 25 July 2005   

import java.util.*;

class CalculatorApp {

    // ------------------- FIELDS ------------------------ 
        
    // Create Scanner class instance
    private static Scanner input = new Scanner(System.in);
    
    // ------------------ METHODS ------------------------  
    
    /** Main method */
    
    public static void main(String[] args) {
	/* Input */
	System.out.println("Write a simple arithmetic expression");
	System.out.println("('*'=42, '+'=43, '-'=45, '/'=47):");
	int newOp1 = input.nextInt();
	char newOp = (char) input.nextInt();
	int newOp2 = input.nextInt();
	
	/* Create instance of type Calculator */
	Calculator newCalculator = new Calculator(newOp1,newOp,newOp2);
	
	/* Check input */	
	if (newCalculator.inputCheck()) System.out.println("Answer = " + 
			newCalculator.makeCalculation());
	}
    }

Table 3: Calculator application class implementation


3.5 Testing

1. Path Testing: We should test all paths through the system (path testing). As there are a lot of these (see Figure 5) it is a good idea to subdivide the testing to address individual methods where different paths exists, makeCalculation, division and inputCheck. For our purposes we will consider the inputCheck method in isolation.

2. Boundary Value Analyses (BVA) and Limit Testing: Where certain ranges of input are specified we should test at these limits and just above and below these limits. With respect the inputCheck method we should also exercise both paths and both parts of the Boolean expressions involving a logical 'or'. A suitable set of test cases combining path tests and BVA and limit tests for the inputCheck method is given in the table to below.

TEST CASEEXPECTED RESULT
op1oper.op2OUTPUT
46339* 463392147302921
46340* 463402147395600
46341* 46341Error
-46339*-463392147302921
-46340*-463402147395600
-46341*-46341Error

3. Arithmetic Testing We will combine the arithmetic testing with the additional path testing we must under take. The makeCalculation method has five paths. Four for the recognised operators and 1 where the operator is not recognised. This suggests at least five test cases. Combining this with requirements for arithmetic testing the sequence of test cases presented below is suggested.

TEST CASEEXPECTED RESULT
op1oper.op2OUTPUT
10+ 10 20
10+ 0 10
10+-10 0
0+ 10 10
0+ 0 0
0+-10-10
-10+ 10 0
-10+ 0-10
-10+-10-20
TEST CASEEXPECTED RESULT
op1oper.op2OUTPUT
10- 10 0
10- 0 10
10--10 20
0- 10-10
0- 0 0
0--10 10
-10- 10-20
-10- 0-10
-10--10 0
TEST CASEEXPECTED RESULT
op1oper.op2OUTPUT
10* 10 100
10* 0 0
10*-10-100
0* 10 0
0* 0 0
0*-10 0
-10* 10-100
-10* 0 0
-10*-10 100
TEST CASEEXPECTED RESULT
op1oper.op2OUTPUT
10/ 101
10/ 0Error
10/-10-1
0/ 100
0/ 0Error
0/-100
-10/ 10-1
-10/ 0Error
-10/-101
TEST CASEEXPECTED RESULT
op1oper.op2OUTPUT
10%10Unrecognised operator:

4. Data validation testing: This should also be done.

Given the large amount of testing that is to be undertaken a test program is appropriate. A suitable program is given in table 4.

// CALCULATOR TEST APPLICATION
// Frans Coenen
// Thursday 25 March 1999
// The University of Liverpool, UK   

import java.io.*;

class CalculatorTestApp {

    // ------------------ METHODS ------------------------  
    
    /* Main method */
    
    public static void main(String[] args) {
    	testCalculator1('+');
	testCalculator1('-');
	testCalculator1('*');
	testCalculator1('/');
	
	// erroneous operator
	
	testCalculator3(10,'%',10);

	// Test input checks */

	testCalculator3(46339,'*',46339);
	testCalculator3(46340,'*',46340);
	testCalculator3(46341,'*',46341);
	testCalculator3(-46339,'*',-46339);
	testCalculator3(-46340,'*',-46340);
	testCalculator3(-46341,'*',-46341);
	}

    /* Test calculator 1 */

    public static void testCalculator1(char opp) {
    	testCalculator2(10,opp);
	testCalculator2(0,opp);
	testCalculator2(-10,opp);
	}

    /* Test calculator 2 */

    public static void testCalculator2(int op1, char opp) {
    	testCalculator3(op1,opp,10);
	testCalculator3(op1,opp,0);
	testCalculator3(op1,opp,-10);
	}

    /* Test calculator 3 */

    public static void testCalculator3(int newOp1, char newOp, 
    							int newOp2) {
    	Calculator newCalculator;

	/* Create instance of type Calculator */

	newCalculator = new Calculator(newOp1,newOp,newOp2);
	
	/* Check input */

	System.out.print(newOp1 + " " + newOp + " " + newOp2 + " ");
	if (newCalculator.inputCheck()) System.out.println("Answer = " +
			newCalculator.makeCalculation());
	}
    }

Table 4: Calculator application test harness




4. FURTHER EXAMPLE ILLUSTRATING THE USE OF THE JAVA SWITCH STATEMENT.

  1. Date validation.



Created and maintained by Frans Coenen. Last updated 10 February 2015