Return to lecture notes index

15-100 Lecture 18 (Friday, February 25, 2005)

switch statements

A swich statement is a modified form of a series of if statements. It takes one variable (has to be a numerable primative type such as int, long, or char) Rememeber in our NameGame there was a section of code where we kept on refering to the user input (choice) to figure out what the user wanted us to do. Since choice is an int we can use The switch statment as a new way to implement this series of code. The switch statment takes the general form:

 
switch (expression) {
  case VAL:  //choice ==1
    //blah
  case VAL:  //choice == 2
    //blah
  case VAL:  //choice == 3
    //blah
    ...
  default:   //any value of choice
}

The switch statment starts with switch...a reserved word in java that signals the start of a switch statement. The expression should be the value that you want to compare to each of the case values. You can have as many "case VAL:" as you need. The code after case VAL: will run when the expression == VAL. You must end your switch statment with a "default:" case. This is the case that will run if the expression didn't equal any of the cases in the switch statement. After each of these cases you write the code you want the program to run if that case is true.

Because the switch statement only runs when the expression == VAL you can only use the numerable primatives. It makes no sense to try to use the == on strings (remember you have to use the .equals() method on strings) or doubles (there could always be one more point of precision. However ints and chars fit the bill nicely because they have a fixed value that won't change.

An interesting feature of the switch statement is that once a case is evaluated as true all code after the true case will evalute unless you put in the reserved word "break;" (remember that we have seen this before in the context of exiting a while loop). The switch statement is like a big switch in the sky. Once that switch changes states (due to a case being true) all following code will be run until the switch statement is over (so break causes the program to exit from the switch statement). If you forget to write break you will find your code doing weird and mysterious things... namely executing code that it shouldn't be doing. So here's a switch statment with some breaks missing:


switch(x){
  case 1: 
    System.out.println("x == 1.  See... x = " + x);
  case 2:
    System.out.println("x == 2.  See... x = " + x);
    break;
  case 3:
    System.out.println("x == 3.  See... x = " + x);
  default:
    System.out.println("What does x equal? x = " + x);
}

Since we forgot to put break in case 1, if x = 1 our code will print:

x == 1.  See... x = 1
x == 2.  See... x = 1

If the code runs with x = 3 then it will print:

x == 3.  See... x = 3
What does x equal? x = 1

Sometimes this behavior can be used to our advantage. If you want the same code to execute when x == 1 or x == 2. The lack of a break for case 1 will cause the case 2 code to run. If you want the exact same code to run you just leave case 1 empty. However if you want basically the same code done for case 1 and case 2 you can add the extra code in the earlier case and the second case won't run it.

Here's NameGame (which makes use of Menu...see last two days of notes) with it's series of if statements turned into a switch statement (note switch statements don't really reduce amount of code we have to write, but it does make it easier to follow the logic...its easy to see that it is all based on one variable...and thus quicker to read and (possibly) to write.):


import java.io.*;

class NameGame{
  private String firstName;
  private String middleName;
  private String lastName;
  
  public NameGame(String firstName, String middleName, String lastName){
    this.firstName =firstName;
    this.middleName = middleName;
    this.lastName = lastName;
  }
  
  public void printFirstName(){
    System.out.println(firstName);
  }
  
  public void printMiddleName(){
    System.out.println(middleName);
  }
  
  public void printLastName(){
    System.out.println(lastName);
  }
  
  public static void main(String[] args){
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
    String menuString = "1) Create nameGame \n" +
              "2) Print first name \n" +
              "3) Print middle name \n" +
              "4) Print last name \n" +
              "5) Quit \n" ;
    
    int numberOfChoices = 5;
    
    Menu nameMenu = new Menu(menuString, numberOfChoices);
    
    while (true) {
      nameMenu.display();
      //initalize it to an obviously wrong choice.  If you don't initalize it
      // the complier will yell at you.  Saying that choice might not be initalized 
      //because it is in a try block.  
      int choice = -1;
      try{
        choice = nameMenu.getChoice();
      }
      catch (Menu.MenuException me){ //need the Menu. b/c the MenuException is nested w/in the Menu class thus to get MenuException you need to call on Menu class w/ the scope operator "."
        System.out.println(me.getMessage());
        continue; //this will cause java to skip the rest of the while loop and start at the loop's top again
      }
      NameGame game = null;
      switch (choice) {
        case 1:
          String firstName="", middleName="", lastName="";
          try {
            System.out.println("First> ");
            firstName = br.readLine();
            
            System.out.println("Middle> ");
            middleName = br.readLine();
          
            System.out.println("Last> ");
            lastName = br.readLine();
          }
          catch (IOException ioe){
            System.out.println("An error occured while reading input. Please try again.");
            continue;
          }
          game = new NameGame(firstName, middleName, lastName);
          break;
      
        case 2:
          game.printFirstName();
          break;
              
        case 3:
          game.printMiddleName();
          break;
    
        case 4:
          game.printLastName();
          break;
    
        case 5: 
          return;
        default:
          System.out.println(choice + " not an option.");
          //can now comment out that sanity check...leave in return choice
      }//end of case (choice)      
    }//while
  }//main(...)
}//class NameGame
More loops (do-while, for)

So here is the while loop that we all know and love:


while(predicate){
//blah
}

We can mutate the while loop into a do-while loop. This loop executes the code in the do's body and returns to the top of the loop if the while's predicate is true. This makes the do-while loop a post-test loop. It tests the predicate at the end. So this means that the do loop is gaurenteed to run at least once. This is a good way to do a loop if you need to initalize a variable in the same way that you would be doing the loop. So here is the do-while loop's general form:

do{
  //blah
}while(predicate) 
Here is another permutation of the while loop. It is an infanate loop and this allows you to make the break condition come in the middle of the while loop's body. Note that because this is a continuous loop a reader has no clue as to when this loop will break. As the programmer it is our job to make sure to document the break condition very clearly at the top of the loop some carefully worded comments. In Kesden's words, "it does x, checks y (bails if fails), then does z.":
while(true){
  //step 1
  if(!predicate)
    break;
  //step 2
}
Here is another use of the while loop (very similar to what we did in NameGame to make the game "give up" if the user entered too many false choices.
int tryNumber = 1;
while (tryNumber <=3) {
  //give user a chance
  if (successful) 
    break;
  tryNumber++;
}

Note that in the while loop above, there are four main parts: (1) the initialization of the loop variable, tryNumber, to zero, (2) the increment of the loop variable at the bottom of the loop, (3) the predicate, which is the test performed by the loop to see whether or not to continue the loop (this is a pre loop test), in this case tryNumber < 3, and (4) the body of the loop, where we give the user a chance and break if successful.

This is another case where programming languages make the common case convenient. There's another type of loop in Java, the for loop, that allows parts (1), (2) and (3) above to be done in one line...the for loop:


for (int tryNumber = 1; tryNumber <= 3; tryNumber++){
  //give user a chance
  if (successful) break;
}

Side note: tryNumber only has scope within the for loop other than that this block of code is exactly similar to the above while loop that terminates after the third try. Also you will find that typically programmers use "tryNumber < 4". It is equivalent to what we have now. This came about historically because it took less time to do a < as opposed to a <=. This now doesn't matter. But now if you ever see this anarchism at work you will know why.


public class LoopExamples (
  public static void main(String [] args) {
    int counter = 1;
    while (counter <=10){
      System.out.println(counter);
      counter++;
    }
  }
}//prints 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 (only with each number on it's own line.)

If you change code to:

int counter = 1;
while(counter<=10){
  System.out.println (counter)
  counter += 2;
}//prints 1, 3, 5, 7, 9 
//(next is 11 so predicate evaluates to false and the loop exits)

Change the initiation of counter and you can get the even numbers to print:

int counter = 2;
while(counter<=10){
  System.out.println (counter)
  counter += 2;
}// prints 2, 4, 6, 8, 10

You can also count backwards:

int counter = 10; 
while(counter > 0)
  System.out.println(counter)
  counter--;
}// prints 10, 9, 8, 7, 6, 5, 4, 3, 2, 1

Let's mutate the above code into a for loop
for(int counter = 10; counter > 0; counter--){
  System.out.println (counter);
}

This is equivalent to previous while loop except for the fact that counter has a bigger scope. You could make them exactly the same by putting pointless brackets around the whole while and counter code like this:


{
  int counter = 10; 
  while(counter > 0) {
    System.out.println(counter)
    counter--;
  }
}