Simple Decision Structures

A decision structure is a construct in a computer program that allows the program to make a decision and change its behavior based on that decision. The decision is made based on the outcome of a logical test. A logical test is a calculation whose outcome is either true or false.

In today's lecture I will introduce two simple decision structures, the if statement and the switch statement.

If statements

The if statement is the simplest example of a decision structure in Java. In an if statement a logical test is made which can evaluate to either true or false. If the result of the test is true, the statements in the if branch are executed. If the result of the test is false, the statements in the else branch are executed. Once the statements in the appropriate branch have been executed, the flow of execution continues on to the statements that follow the if statement.

Here is a simple example. Below is the code for program that computes and prints the absolute value of a number the user inputs.

public class AbsValue {

  public static void main(String[] args) {
    int x, absX;

    Scanner input = new Scanner(System.in);
    System.out.print("Enter an integer x: ");
    x = input.nextInt();

    // if statement starts below
    if (x < 0) {
      // This is the if branch
      absX = -x;
    } else {
      // This is the else branch
      absX = x;
    }

    System.out.println("The absolute value of " + x + " is " + absX);
  }
}

The test in the if statement is a simple comparison test that checks whether or not the value stored in x is positive. If the test evaluates to true, the code following the test is executed. If the test evaluates to false, the code following the else is executed instead. Note that curly braces are used to delimit the two branches.

The exact placement of the curly braces is a matter of taste. Each of the following forms is legal:

if(x < 0) 
	{
	absX = -x;
  }
else 
  {
	absX = x;
  }

if(x < 0) { absX = -x; }
else { absX = x; }

In cases where the body of one of the branches of the if statement reduces to just a single statement, the curly braces are optional.

if(x < 0) 
	absX = -x;
else 
	absX = x;

The else branch is also optional. In cases where the logic requires only that something be done when a particular condition applies, only the if branch may be necessary. For example, we can write the program above this way.

public class AbsValue2 {

  public static void main(String[] args) {
    int x, absX;

    Scanner input = new Scanner(System.in);
    System.out.print("Enter an integer x: ");
    x = input.nextInt();
    
    absX = x;
    if (x < 0) 
      absX = -x;

    System.out.println("The absolute value of " + x + " is " + absX);
  }
}

Comparison tests

The next few example programs we are going to see are all programs that do numerical calculations. In numerical programs, most decisions are made on the basis of numerical comparisons. The table below shows the comparison operators available for use in Java.

OperatorMeaning
==is equal to
!=is not equal to
<is less than
<=is less than or equal to
>is greater than
>=is greater than or equal to

Important warning: note that the comparison operator for equality is ==, not =. This leads to one of the more common mistakes that beginning Java programmers make. The follow code is legal, but does not do what you might expect.

if(n = 10)
  n = 0;

What happens in this case is that rather than testing whether or not n equals 10, the code in the test actually sets n equal to 10. (After that the code in the if branch gets executed anyway, regardless of the original value of n.)

Nested if statements

An if statement gives us the ability to ask a single question and do something in response to that question. Often, the logic of a particular situation will dictate that we ask more than one question to resolve a situation. In that case, we may need to make use of a nested if. The following example demonstrates how this works in practice. The program below has the user enter three floating point numbers that form the coefficients of a polynomial p(x) = a x2 + b x + c. The program will then try to determine what the roots of that polynomial are and print the roots.

The key decision that has to be made is based on the value of the descriminant, b2 - 4 a c. If that quantity is negative, the polynomial has no real roots. If it 0, the equation has one real root, and if it is greater than 0 there are two distinct real roots. The program below uses a pair of nested if statements to determine which of these three cases we are dealing with.

public class PolynomialRoots {
  public static void main(String[] args) {
    double a,b,c,desc;

    Scanner input = new Scanner(System.in);
    System.out.print("Enter the coefficients a, b, and c: ");
    a = input.nextDouble();
    b = input.nextDouble();
    c = input.nextDouble();
    
    desc = b*b - 4*a*c;
    
    if(desc < 0.0) {
      // First case - no real roots
      System.out.println("The polynomial has no real roots.");
    }
    else {
      // Second case - one or two real roots
      if(desc == 0.0){
        double root = (-b+Math.sqrt(desc))/(2*a);
        System.out.println("The polynomial has one root, " + root);
      }
      else {
        double root1 = (-b-Math.sqrt(desc))/(2*a);
        double root2 = (-b+Math.sqrt(desc))/(2*a);
        System.out.println("The polynomial has two roots, " 
           + root1 + " and " + root2);
      }
    }
  }
}

The first if test distinguishes between the case where there are no real roots and the case where there are real roots. Within the second case we have to ask a further question to determine if there is a repeated real root or two distinct real roots. We do this by simply placing a second if statement inside the else part of the first if statement.

Chained if-else statements

The example above is an example of a categorization task. The answer we are looking for can fall into one of three categories, so we ask a couple of questions to determine which of the three categories we have. Note that to accomplish the categorization we have to nest the if statement that asks the second question inside the else part of the if statement that asks the first question.

Since an entire if-else construct is considered to be a single compound statement in Java, we can take advantage of the special rule that says that if the if or else part of an if-else statement reduces to just a single term we can eliminate the curly braces. Deploying that rule converts the structure of the code to something like this:

if(desc < 0.0) {
   System.out.println("The polynomial has no real roots.");
}
else
  if(desc == 0.0){
    double root = (-b+Math.sqrt(desc))/(2*a);
    System.out.println("The polynomial has one root, " + root);
  }
  else {
    double root1 = (-b-Math.sqrt(desc))/(2*a);
    double root2 = (-b+Math.sqrt(desc))/(2*a);
    System.out.println("The polynomial has two roots, " 
        + root1 + " and " + root2);
  }

Eliminating the line break between the else and if and modifying the structure slightly produces this form.

if(desc < 0.0) {
   System.out.println("The polynomial has no real roots.");
}
else if(desc == 0.0){
   double root = (-b+Math.sqrt(desc))/(2*a);
   System.out.println("The polynomial has one root, " + root);
} else {
   double root1 = (-b-Math.sqrt(desc))/(2*a);
   double root2 = (-b+Math.sqrt(desc))/(2*a);
   System.out.println("The polynomial has two roots, " 
        + root1 + " and " + root2);
}

The resulting form is identical syntactically and functionally to the nested-if form we started with above. This so-called chained if-else form is very useful for categorization. Using this form we can ask a series of questions designed to determine which of several categories applies in a given situation.

Here is an example from the text. ComputeBMI.java computes a Body Mass Index in much the same way we did in an exercise in the first lab. To make that index more meaningful, the program also provides interpretation. There is a BMI scale that can be used to determine whether a person is seriously underweight, underweight, normal weight, overweight, or seriously overweight. The program uses a chained if-else construct to determine which of these five categories the user's BMI places them in.

public class ComputeBMI {
  public static void main(String[] args) {
  Scanner input = new Scanner(System.in);
  
  // Prompt the user to enter weight in pounds
  System.out.print("Enter weight in pounds: ");
  double weight = input.nextDouble();
  
  // Prompt the user to enter height in inches
  System.out.print("Enter height in inches: ");
  double height = input.nextDouble();
  
  final double KILOGRAMS_PER_POUND = 0.45359237; // Constant
  final double METERS_PER_INCH = 0.0254; // Constant 
  
  // Compute BMI
  double bmi = weight * KILOGRAMS_PER_POUND / 
    ((height * METERS_PER_INCH) * (height * METERS_PER_INCH));

  // Display result
  System.out.println("Your BMI is " + bmi);
  if (bmi < 16)
    System.out.println("You are seriously underweight");
  else if (bmi < 18)
    System.out.println("You are underweight");
  else if (bmi < 24)
    System.out.println("You are normal weight");
  else if (bmi < 29)
    System.out.println("You are overweight");
  else if (bmi < 35)
    System.out.println("You are seriously overweight");
  else
    System.out.println("You are gravely overweight");
  }
}

Compound tests

Some questions we would like to ask can not be phrased readily as simple comparisons. To make it possible to form more complex tests, Java allows you to form compound tests by combining simple tests with logical operators. The table below shows the three logical operators that can be used to form compound tests.

operatorinterpretation
&&logical and
||logical or
!logical negation

Compound tests are formed in a fairly natural way by combining simple tests. For example, here is a compound test to determine whether or not the integer variable x falls in the range between 5 and 10, inclusive.

if((x >= 5)&&(x <= 10))
  System.out.println("x falls in the range [5,10]");

Here is another example that uses a compound test. To determine whether or not a given year is a leap year, we have to use the following rules.

The test to determine whether or not a year is a leap year is best accomplished with a compound test, as this code shows:

if(((year % 4 == 0)&&(year % 100 != 0))||(year % 400 == 0))
  System.out.println("The year " + year + " is a leap year");
else
  System.out.println("The year " + year + " is not a leap year");

switch statements

We saw above that you can use a chained if-else construct to determine which of several categories something falls in. A very common special case of this problem occurs when we have a limited number of categories that can be labeled by individual integer values. To handle that special case, Java offers a special decision structure called the switch statement. Here is an example of switch statement in use. The program below prompts the user to enter an integer in the range from 0 to 9, and then converts the integer they entered into its text equivalent. This is a categorization task that involves putting ourselves in one of 10 distinct categories that can be labeled by integer values.

public class IntToString {
  public static void main(String[] args) {
    int x;
    String word;

    Scanner input = new Scanner(System.in);
    System.out.print("Enter an integer between 0 and 9: ");
    x = input.nextInt();

    switch(x) {
      case 0:
        word = "zero";
        break;
      case 1:
        word = "one";
        break;
      case 2:
        word = "two";
        break;
      case 3:
        word = "three";
        break;
      case 4:
        word = "four";
        break;
      case 5:
        word = "five";
        break;
      case 6:
        word = "six";
        break;
      case 7:
        word = "seven";
        break;
      case 8:
        word = "eight";
        break;
      case 9:
        word = "nine";
        break;
      default:
        word = "invalid";        
    }
    
    System.out.println("The integer you entered is " + word);
  }
}

The switch statement begins with

switch(x)

where x is the value of the variable whose value we wish to categorize. The body of the switch statement consists of a series of cases. Each case has a case label ending with a :, some code to be executed when x falls into that case, and a break statement to mark the end of the case. At the end of the body of the switch statement we also have a default case that says what to do when none of the cases above apply.

Programming Exercises

Here are two short programming exercises for you to try. These exercises are not to be turned in. I will show my solution to these two exercises in class on Monday.

1. Here is some code from chapter 2 in the text for a program that determines how many dollars, quarters, dimes, nickels, and pennies are in a given dollar amount.

public class ComputeChange {
  public static void main(String[] args) {   
  // Create a Scanner
  Scanner input = new Scanner(System.in);

  // Receive the amount 
  System.out.print(
    "Enter an amount in double, for example 11.56: ");
  double amount = input.nextDouble();

  int remainingAmount = (int)(amount * 100);

  // Find the number of one dollars
  int numberOfOneDollars = remainingAmount / 100;
  remainingAmount = remainingAmount % 100;

  // Find the number of quarters in the remaining amount
  int numberOfQuarters = remainingAmount / 25;
  remainingAmount = remainingAmount % 25;

  // Find the number of dimes in the remaining amount
  int numberOfDimes = remainingAmount / 10;
  remainingAmount = remainingAmount % 10;

  // Find the number of nickels in the remaining amount
  int numberOfNickels = remainingAmount / 5;
  remainingAmount = remainingAmount % 5;

  // Find the number of pennies in the remaining amount
  int numberOfPennies = remainingAmount;

  // Display results
  String output = "Your amount " + amount + " consists of \n" + 
    "\t" + numberOfOneDollars + " dollars\n" + 
    "\t" + numberOfQuarters + " quarters\n" +
    "\t" + numberOfDimes + " dimes\n" + 
    "\t" + numberOfNickels + " nickels\n" +
    "\t" + numberOfPennies + " pennies";
  System.out.println(output);
  }
}

Modify this program to be more intelligent in how it prints out the result. If a given denomination does not appear in the result, don't print anything for that denomination. If the amount for a given denomination is 1, print the singular form of that denomination; otherwise, use the plural form. For example, given the input 11.87, your program should print

Your amount 11.87 consists of
11 dollars
3 quarters
1 dime
2 pennies

2. Write a program that prompts the user for the month and year and prints a message saying how many days are in that month. For example, on the input 3 2009 your program should print

There are 31 days in the month 3 2009.

On the input 2 2000 your program should print

There are 29 days in the month 2 2000.