15-100 Lecture 9 (Monday, June 8, 2006)

A Simple Tangle

Let's write some quick code. Given a user's choice, represented as a char, let's print my 'F'irst, 'M'iddle, or 'L'ast name, or 'Q'uit.

  boolean quit = false;

  while (!quit) {

    // Display the menu
    System.out.println ("");
    System.out.println ("");
    System.out.println ("--- Menu ---");
    System.out.println ("F)irst name");
    System.out.println ("M)iddle name");
    System.out.println ("L)ast name");
    System.out.println ("Q)uit");
    System.out.println ("");
    System.out.println ("Enter your choice: ");

    // Get choice
    String choiceString = br.readLine();
    char choice = choiceString.toUpperCase().charAt(0); 


    // Decide what to do -- and do it
    if (choice == 'F') 
      System.out.println ("Gregory");
    else 
      if (choice == 'M')
        System.out.println ("Michael");
      else 
        if (choice == 'L')
          System.out.println ("Kesden");
        else
          if (choice == 'Q')
            quit = true; // or break
          else
            System.out.println ("Please select F, M, L, or Q.");
  }
  

Notice how nested that code became. Does it have to be that complicated? Well, we can rewrite it and make it a bit better. To do that, we'll bail as soon as we get a match, so we can eliminate the nesting:

  boolean quit = false;

  while (!quit) {

    // Display the menu
    System.out.println ("");
    System.out.println ("");
    System.out.println ("--- Menu ---");
    System.out.println ("F)irst name");
    System.out.println ("M)iddle name");
    System.out.println ("L)ast name");
    System.out.println ("Q)uit");
    System.out.println ("");
    System.out.println ("Enter your choice: ");

    // Get choice
    String choiceString = br.readLine();
    char choice = choiceString.toUpperCase().charAt(0); 


    // Decide what to do -- and do it
    if (choice == 'F') { 
      System.out.println ("Gregory");
      continue;
    }

    if (choice == 'M') {
      System.out.println ("Michael");
      continue;
    }

    if (choice == 'L') {
      System.out.println ("Kesden");
      continue;
    }

    if (choice == 'Q') {
      quite = true; // Or simply, "break;" and skip the next line
      continue;
    }

    System.out.println ("Please select F, M, L, or Q.");
  }
  

The above construction is better. But, it highlights the problem. We're trying to make a one-of-n decision, given a construct, the if-else, that is designed to make a one-of-two decision. So, we basically build up the the right number of choices in powers of two.

The Switch Statement

Java's switch statement is designed to support decision making where there are more than two possibilities. You provide a laundry-list of possibilities. Which of them, if any, are selected depend on a single predicate.

Within the switch statmeent, there is a laundry list of "cases". Execution procedes down this laundry list. Nothing happens until one of the cases actually matches the value of the predicate. At that point, a "big switch in the sky" is thrown and everything thereafter is executed. And, everything means everything -- even if it is associated with a case that doesn't match. This is because the switch is already thrown.

To avoid this behavior, so that exactly one path can be selected, the code associated with each case is often followed by a "break statment". It works as it did within a loop. A "break" casues control to immediately leave the switch and pick up after it.

Additionally, the "default" case can be specified. This case matches anything. It alwasy cases the great switch in the sky to be turned on.

This is best illustrated with an example. Let's consider our program of last class, rewritten using a switch.

Detangled with Switch

Rememebr this program? Look how pretty it is:

  boolean quit = false;

  while (!quit) {

    // Display the menu
    System.out.println ("");
    System.out.println ("");
    System.out.println ("--- Menu ---");
    System.out.println ("F)irst name");
    System.out.println ("M)iddle name");
    System.out.println ("L)ast name");
    System.out.println ("Q)uit");
    System.out.println ("");
    System.out.println ("Enter your choice: ");

    // Get choice
    String choiceString = br.readLine();
    char choice = choiceString.toUpperCase().charAt(0); 


    // Decide what to do -- and do it
    switch (choice) {

      case 'F':
        System.out.println ("Gregory");
        break;

      case 'M':
        System.out.println ("Michael");
        break;

      case 'L':
        System.out.println ("Kesden");
        break;

      case 'Q':
        // Notice: Can't just break here -- we'd leave the switch, not the loop
        quit = true; 
        break;

      default: 
        // Since this is the last case, not strictly necessary, but good form
        System.out.println ("Please select F, M, L, or Q.");
        break; 
    
    }

  }
  

...wasn't that nice?

A Closer Look at the Break (or Absence, Thereof)

Now, let's take a closer look at the break. Let's see how we can avoid the need to upperCase() the string, by accepting either lower- or upper-case, directly.

  boolean quit = false;

  while (!quit) {

    // Display the menu
    System.out.println ("");
    System.out.println ("");
    System.out.println ("--- Menu ---");
    System.out.println ("F)irst name");
    System.out.println ("M)iddle name");
    System.out.println ("L)ast name");
    System.out.println ("Q)uit");
    System.out.println ("");
    System.out.println ("Enter your choice: ");

    // Get choice
    String choiceString = br.readLine();
    char choice = choiceString.charAt(0);


    // Decide what to do -- and do it
    switch (choice) {

      case 'f':
      case 'F':
        System.out.println ("Gregory");
        break;

      case 'm':
      case 'M':
        System.out.println ("Michael");
        break;

      case 'l':
      case 'L':
        System.out.println ("Kesden");
        break;

      case 'q':
      case 'Q':
        // Notice: Can't just break here -- we'd leave the switch, not the loop
        quit = true; 
        break;

      default: 
        // Since this is the last case, not strictly necessary, but good form
        System.out.println ("Please select F, M, L, or Q.");
        break; 
    
    }

  }
  

Take a look at the back-to-back use of upper- and lower-cases. This works because there is no break after the first case -- only the second. So, if the lower case "turns the switch on", it stays on until it hits the break.

Switch Statment, Important Notes

A few things to keep in mind: