Witscale Test Center

5.2 Conditional statements: if, if-else and switch > 5.2.3 The switch statement


5.2.3 The switch statement

Despite indentations, the complex version of multiple if-else statements has poor readability. If these if-else statements are checking conditions on a single argument, you can replace them with a switch statement, which has better readability. Table 5.2 shows multiple if statements and their equivalent switch statements. It also illustrates how the switch statement is cleaner to read than the nested if-else statements.

 

Table 5.2 Nested if statement and equivalent switch statement.

 

Nested if statements

Equivalent switch statement

int number = 10;

if (number == 5) {

System.out.println("number=5");

} else if (number == 10) {

  System.out.println("number=10");

} else if (number == 20) {

System.out.println("number=20");

} else {

  System.out.println("not found");

}

int number = 10;

switch (number) {

 case 5 :    

         System.out.println("number=5");

         break;

 case 10 :

         System.out.println("number=10");

         break;

 case 20 :

         System.out.println("number=20");

         break;

 default :

         System.out.println("not found");

         break;

}

 

The case statements correspond to the conditions we wish to check in the if statements. The default statement is normally executed when none of the case statements is matched. Note the break statement at the end of each case statement. It is used to discontinue the execution.

 

Arguments to the  switch and case statements

The general format of switch statements:

 

switch(expression){

  case constantExpression: statement(s);

  case constantExpression: statement(s);

  .

  .

  .

  default: statement(s);

 

}

The arguments to switch and case statements must follow certain rules.

The type of the expression in switch argument must be an int. The compatible data types to int such as char, byte, short are also allowed. These data types are narrower (see chapter 10) that int datatype. Hence, they can be assigned to an int variable. Java allows storing a-value-of-a-narrower-datatype into a-variable-of-wider-datatype, as there is no loss of information in such case. However, an object reference cannot be passed to a switch or case statement.

The type of the constantExpression in the case statement must be the same as the switch argument. For example, if the switch argument is of byte type, the constant expression in the case statement must be evaluated to a value of byte type. The following code snippet won’t compile. Since a byte type has the range of -12 to 127, the case argument 128 is a bigger value for the byte datatype. The type of case argument 128 is int. It is not compatible with the type of the switch argument, b. Therefore, the compiler throws an error at case 128.

byte b = 126;

switch(b) {

 case 100:

 case 125:

 case 128:

}

The important point here is that the case argument’s type must be compatible to the data type of the switch argument. Do not worry if you don’t understand this right now. The range of values that each data type can hold and the data type compatibility will be discussed in chapter 10.

 If the value of a wider data type such as long is passed to a switch or case argument, a compile-time error occurs. As the switch accepts int arguments, passing long will require casting it to int.

 

You may face questions in exam where you will be tested on these rules. For instance, you will need to identify invalid arguments to the switch or case statements.

 

The case statements

Similar to the switch argument, the expressions in the case statements must abide to certain rules:

Every case expression must be a constant expression. A constant expression is an expression that can be evaluated at compile time. For that, all the values in the expression should be known at compile-time. For instance, in the following example, (choice +1) is not allowed, as it is not a constant expression. The value of choice can be anything[‡‡‡‡‡‡‡] at runtime; therefore, it cannot be a part of a constant expression.

int choice = 15;

switch(choice) {

 case (14 + 39) :System.out.println(“Allowed”);

                 break;

 case (15 + 2) : System.out.println(“Allowed”);

                 break;

 case (choice +1):System.out.println(“Not allowed”);

                 break;

}

 

The case statement can also have a numeric literal or static final variable. Both of them have a known fixed value in the code. For instance, in the following code the variable sure can be used in the case statement. However, the case for notSoSure won’t compile. The case argument notSoSure is not a constant and hence not known at compile-time. Therefore, the compiler flags an error saying, “case expressions must be constant expressions”.

 

final int sure = 100;

int notSoSure = 50;

int choice;

choice = readChoice();

switch(choice) {

 case sure: System.out.println(“Solid like a rock”);

                 break;

 case notSoSure: System.out.println(“50/50”);

                 break;

}

 

Every case expression must be evaluated to be unique. If expressions in two case statements in a switch are evaluated to a same value, the compiler throws an error. This is reasonable as in such cases Java cannot decide which one of the two case statements to execute if the constant expression matches with the switch argument. For example, the following code will fail to compile:

int choice = 15;

switch(choice) {

 case 15: System.out.println(“To be”);

          break;

 case 15: System.out.println(“Not to be”);

          break;

}

 

The default case

The default statement is executed when none of the case statements is matched with the switch argument. It is an optional statement. There can be at the most only one default statement in a switch. Most of the time, you will see the default defined at the bottom in switch. The default statement makes more sense there as it is executed by default after every other case is checked for a match. Syntactically, however, the order of case statements and default can be anything. For example, in the code below, the default is defined as the second statement, but it will still be executed if all other case statements do not match the switch argument. Following is a valid code snippet.

 

int number = 12;

switch (number) {

 case 5 :    

System.out.println("number=5");

     break;

default :

     System.out.println("not found");

     break;

case 10 :

System.out.println("number=10");

     break;

case 20 :

System.out.println("number=20");

     break;

}

 

If none of the case statements matches with the switch argument and there is no default statement, the switch statement does nothing. The control simply transfers to the next line after the switch block.

 

The break statement and the control fall through the case statements

The break statement is used at the end of a case statement, to discontinue the execution. Whenever the program encounters the break statement, the execution immediately jumps out of switch block to the next statement after the block. If it is absent, the execution control falls through to execute all the remaining case statements and the default statement (if any) until a break is found or the switch statement ends. If you do not want the control to fall through you must give a break for each case statement.

 

It is redundant to give a break statement for the last statement in a switch statement as control comes out of the switch after that anyway.

 

Table 5.3 demonstrates the difference in switch statements with and without the break statement. In a switch statement with a break, when the matching case for 5 is found it is executed, the control comes out of the switch due to the break statement. In switch statement without break, when the matching case for 5 is found it is executed; then the control falls through and the remaining case statements and the default statement are executed, even though they do not match the switch argument.

 

 

Table 5.3 The switch statement with and without break statements

 

 

With break statements

Without break statements

Switch

Statements

 

int number = 5;

switch (number) {

 case 1:System.out.println("number=1");

                  break;

 case 2:System.out.println("number=2");

                  break;

 case 3:System.out.println("number=3");

                  break;

 case 5:System.out.println("number=5");

                  break;

 case 7:System.out.println("number=7");

                  break;

 default:System.out.println("not found!");

                  break;

}

System.out.println("After switch”);

 

 

int number = 5;

switch (number) {

 case 1:System.out.println("number=1");

 case 2:System.out.println("number=2");

 case 3:System.out.println("number=3");

 case 5:System.out.println("number=5");

 case 7:System.out.println("number=7");

 default :System.out.println("not found!");

}

System.out.println("After switch”);

Output

number=5

After switch

number=5

number=7

not found!

After switch

 

The falling of control through multiple case statements is especially useful when you want to execute a common code when any of these multiple cases is matched. For example, if you wish to match case for a single digit prime number and display a message if any match is found, you can do so by writing empty an case for each one except the last case. The code snippet below displays a message “number is a single digit prime number” if the number is either 1 or 2 or 3 or 5 or 7. If none of the cases is matched, the default is executed.

 

int number = 2;

switch (number) {

 case 1:

 case 2:

 case 3:

 case 5:

 case 7:System.out.println("number is a single digit prime number");

        break;

 default:System.out.println("number is not a single digit prime number");

}