Welcome to Lesson 10!


Learning Objectives
  • What is a switch statement?
  • How does a switch statement compare to an if statement?
  • What is the syntax of a switch statement?
  • What is "fall through"?
  • How do you format decimal numbers for printing
  • What is a final and how do you declare one?
  • What is are magic numbers and why should they be avoided?
  • What are the short cut assignment operators for add, subtract, multiply, divide, and modulus?
  • What are the increment and decrement operators?
    • What is the difference between pre and post increment and decrement?
  • What is casting?
    • How do you cast an integer to a double and a double to an integer?


Announcements

  • Return Midterms in last 5 minutes of class - excellent results!
    • As: 23 (2 100% scores)
    • Bs: 9
    • Cs: 3
    • Ds: 3
    • Fs: 4
    • No Shows: 2
  • If you are in the C, D, or F range something needs to change about your approach
    • You can still turn it around!
    • Are you doing the homework?
    • Are you paying attention in class? Move to the front.
    • Are you getting help when you are stuck or something is unclear?
    • The class is only going to get harder from here!
  • Quiz 5 and Lab 5 due on Friday
  • Assignment 10 due Thursday

Review Activity
With a partner, answer the following questions on a sheet of paper:

Question 1:

  • What will the following output to the console?
String student1 = "Tanya";
String student2 = "Tasha";

if (student1.compareTo(student2) < 0) {
    System.out.println("Alpha");
} else {
    System.out.println("Beta");
}

Question 2:

  • Imagine that a local radio station is holding a contest to give away a year's supply of free pet food to one lucky winner.
  • To win the contest, you must meet the following criteria:
    • You must be caller 19
    • The pet your own must be one of the following: dog, cat, rabbit
    • You must be between the ages of 18 and 65.
  • Which of the following test conditions will correctly determine the winner of the contest
a. if (numCaller == 19 && (pet == "rabbit" || pet == "cat" || pet == "dog") && (age >= 18 && age <= 65))
System.out.println("You are the winner!");

b. if (numCaller == 19 && (pet == "rabbit" || "cat" || "dog") && (age >= 18 && <= 65))
      System.out.println("You are the winner!");

c. 
if (numCaller == 19 || (pet.equals("rabbit") && pet.equals("cat") && pet.equals("dog")) || (age >= 18 && age <= 65))
      System.out.println("You are the winner!");


d. 
if (numCaller == 19 && (pet.equals("rabbit") || pet.equals("cat") || pet.equals("dog")) && (age >= 18 && age <= 65))
      System.out.println("You are the winner!");

e. 
if (numCaller = 19 && (pet.equals("rabbit") || pet.equals("cat") || pet.equals("dog") && (age >= 18) || age <= 65))
   
System.out.println("You are the winner!");

Question 3:

  • What will the following print to the console?

int age = 20;

boolean is_student = true;

if (is_student || age > 21) {

    System.out.println("Fi!");

}

if (!is_student && age < 21) {

    System.out.println("Fo!");

}

if (is_student && age < 21) {

    System.out.println("Fum!");

}

Importance of Using if-else-if Structure

  • Note that we cannot remove the else portion of the structure like shown below:

        Scanner input = new Scanner(System.in);
        System.out.print("Enter a magnitude on the Richter scale: ");
        double richter = input.nextDouble();
       
        if (richter >= 8.0) { // Does not use else
            System.out.println("Most structures fall");
        }
        if (richter >= 7.0) {
            System.out.println("Many buildings destroyed");
        }
        if (richter >= 6.0) {
            System.out.println("Many buildings considerably damaged, some collapse");
        }
        if (richter >= 4.5) {
            System.out.println("Damage to poorly constructed buildings");
        }
        if (richter >= 3.5) {
            System.out.println("Felt by many people, no destruction");
        }
        if (richter >= 0) {
            System.out.println("Generally not felt by people");
        }
        if (richter < 0) {
            System.out.println("Negative numbers are not valid");
        }

  • The conditions must be exclusive and we need the else-if conditions to ensure exclusivity
  • Independent if statements may cause a single input to print several messages


When Order Matters

  • In some cases, the order of the tests is important
  • For example, look at the following program from displays a description of the likely impact of an earthquake based on its magnitude on the Richter scale

Program Showing Multiple Alternatives Where Order Matters

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static void main(String[] args) {
    Scanner input = new Scanner(System.in);

    System.out.print("Enter a magnitude on the Richter scale: "); double richter = input.nextDouble(); if (richter >= 8.0) { System.out.println("Most structures fall"); } else if (richter >= 7.0) { System.out.println("Many buildings destroyed"); } else if (richter >= 6.0) { System.out.println("Many buildings considerably damaged, some collapse"); } else if (richter >= 4.5) { System.out.println("Damage to poorly constructed buildings"); } else if (richter >= 3.5) { System.out.println("Felt by many people, no destruction"); } else if (richter >= 0) { System.out.println("Generally not felt by people"); } else { System.out.println("Negative numbers are not valid"); } }

Order Is Important

  • Note that the order of the tests is important to ensure that the right results are printed
  • If we rearranged the order of the if-else statements, we would get the wrong results
  • For example, if we reversed the order of the tests:
    if (richter >= 0) { // tests in wrong order
        System.out.println("Generally not felt by people");
    } else if (richter >= 3.5) {
        System.out.println("Felt by many people, no destruction");
    } else if (richter >= 4.5) {
        System.out.println("Damage to poorly constructed buildings");
    } else if (richter >= 6.0) {
        System.out.println("Many buildings considerably damaged, some collapse");
    } else if (richter >= 7.0) {
        System.out.println("Many buildings destroyed");
    } else if (richter >= 8.0) {
        System.out.println("Most structures fall");
    } else {
        System.out.println("Negative numbers are not valid");
    }
    
  • This does not work because all values meet the first condition
  • Every other test will never be attempted


Wrapping Up Conditionals: Switch Statements

  • The switch statement gives us an alternative to an if-else-if chain
  • Executes a section of code depending on value of a variable
  • The general syntax is:
    switch (expression) {
       case label1:
          statements
          break;
       case label2:
          statements
          break;
       ...
       case labeln:
          statements
          break;
       default:
          statements
    }
    
  • Where:
    • expression: a value you want to match
    • labelx: a numeric constant
    • statements: the statements to execute when the condition is met
  • Any number of case labels can be placed in any order
  • Any value that does not match starts executing with the statement after default
  • Execution continues until the end of the switch statement or a break statement
  • The break statement causes an immediate exit from the switch statement
  • Just as case identifies possible starting points, break determines end points

Example of a switch Statement:

public static void main(String[] args) {
	     Scanner input = new Scanner(System.in);
String typeOfDay="";

System.out.print("Enter a day of the week: ");
String dayOfWeek = input.next();

switch (dayOfWeek) {
case "Monday":
typeOfDay = "Weekday";
break;
case "Tuesday":
typeOfDay = "Weekday";
break;
case "Wednesday":
typeOfDay = "Weekday";
break;
case "Thursday":
typeOfDay = "Weekday";
break;
case "Friday":
typeOfDay = "Hurray! End of work week!";
break;
case "Saturday":
typeOfDay = "Weekend";
break;
case "Sunday":
typeOfDay = "Weekend";
break;
default:
System.out.println("Error: Invalid day of the week");

}
System.out.println(typeOfDay);
input.close();
}
  • Notice that each case other than the last contains a break statement
  • Ensures that the switch statement is exited after a matching case is found

When to Use switch Statements

  • Switch statements work for exact matches ONLY
  • They can be used with a limited number of data types in Java:
    • byte, short, char, and int primitive data types.
    • It also works with the String class
    • A few special classes that wrap certain primitive types, which you will learn about in 36B: Character, Byte, Short, and Integer
  • The below example highlights the problem of only being able to look for an exact match
    • For example, we are unable to test for scores using >=
    • Thus, we have to use a clever trick - dividing the score by 10 to retrieve the first digit(s) (1-10)


Another example of switch statements involving ints


public static void main(String[] args) {
        Scanner input  = new Scanner(System.in);

        System.out.print("I show a grade based on a"
            + " score.\nEnter your score: ");
        int score = input.nextInt();

        switch (score / 10) { //integer division to convert score to an int from 1 to 10
            case 10:
            case 9:
                System.out.println("You got an A");
                break;
            case 8:
                System.out.println("You got a B");
                break;
            case 7:
                System.out.println("You got a C");
                break;
            case 6:
                System.out.println("You got a D");
                break;
            default:
                System.out.println("Sorry, an F");
        }
    }



The Case Against Switch Statements
  • Because they can only be used for exact matches (== or .equals()), switch statements are inherently less useful than if-else statements (which can involve test conditions using all 6 comparison operators, including < and >)
  • Also, the syntax is no clearer than if-else statements
  • Note that there is a reason for the limitations of the switch statement
  • Many years ago a compiler could generate more efficient code (using jump tables or binary searches) only within the limitations of the switch statement
  • However, modern compilers are quite capable of optimizing if-else statements to the same degree
  • Thus, we have no reason to ever use a switch statement (depending on your compiler)
  • On the other hand, there are reasons to avoid using a switch statement
  • Every branch of the switch statement must be terminated by a break statement
  • If the break statement is missing, the program falls through and executes the next case without testing
  • There are rare uses for this fall through behavior, such as printing the words for the song, The Twelve Days of Christmas
  • However, according to a study by Peter van der Linden, reported in his book, Expert C Programming, p. 38, the falling through behavior is needed less than 3% of the time
  • Forgetting to type the break statement is a very common error and the source of many bugs
  • Therefore, switch statements are less useful than if statements and potentially more likely to cause bugs in your code.


Example of Fall Through:

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String typeOfDay="";
        System.out.print("Enter a day of the week: ");
        String dayOfWeek = input.next();
        switch (dayOfWeek) {
             case "Monday":
                
             case "Tuesday":
                 
             case "Wednesday":
                 
             case "Thursday":
                 typeOfDay = "Weekday";
                 break;
             case "Friday":
                 typeOfDay = "Hurray! End of work week!";
                 break;
             case "Saturday":

             case "Sunday":
                 typeOfDay = "Weekend";
                 break;
             default:
                 System.out.println("Error: Invalid day of the week");
                
         }
         System.out.println(typeOfDay);
         input.close();
    }



Activity 10.1: Letter Grades (10 pts)
  • Find a partner for pair programming
  • Academic grades in the US are traditionally given as letter grades: A, B, C, D, and F. We need to translate these letter grades into number to calclulate a grade point average (GPA).
  • Write a program that converts a letter grade into it's numerical value using the following conversion table.
    Letter Grade GPA
    A 4.00
    A- 3.67
    B+ 3.33
    B 3.00
    B- 2.67
    C+ 2.33
    C 2.00
    C- 1.67
    D+ 1.33
    D 1.00
    D- 0.67
    F 0.00
  • Find a partner for pair programming, and create a new class LetterGrade.java.
  • In this file, prompt the user for a letter grade of A, B, C, D, or F, possibly followed by a + or -, and no other input as shown in the Example Run.
  • Add the following starter code to the top of the main method.

String grade;
Scanner input = new Scanner(System.in);
System.out.print("Enter a letter grade: ");
grade = input.next();
  • Then, using a switch statement, convert the letter grade into the numerical equivalent shown above.

    Notice that the highest number is 4.0 and that there are no F+ or F- grades. Make sure that the highest grade number is 4.0 and that F+, F and F- are assigned 0.0 values.

  • Display the output using the default formatting and precision for the numbers -- do NOT add any numerical formatting statements to the code.
  • Sample Output: The input prompts and outputs of the program must look like the following for full credit, including the same order of input and wording of the output. For the input shown you must get the same output. However, the output must change properly if the inputs are different.
    Enter a letter grade: B-
    The numeric value is 2.67
    
    Enter a letter grade: A+
    The numeric value is 4.0
    
    Enter a letter grade: F-
    The numeric value is 0.0
    

    In the above three example runs, the user entered "B-", "A+" and "F-" (without the quotes) as the letter grades to convert.

  • After displaying the output, exit the program.
  • When you are finished, both partners should submit the program to Canvas.


Numbers, Formatting and More About Operators

Decimal Formatting

  • Sometimes programs may not display numbers as you would expect!
  • Consider the following program and what it will display:
    public static void main(String[] args) {
        double price = 78.50;
        System.out.println("The price is $" + price);
    }
    
  • We must explicitly tell Java how to output numbers in our programs!
  • These commands do not produce any output but change how System.out outputs floating-point numbers
  • "Magic Formula" to force decimal places:
    System.out.printf("%.2f", value_to_print); 
    
  • % is the place holder representing where you wish to place the value to print inside your message
  • .2f indicates that the floating point value should be printed to 2 decimal places
  • Once we set the decimal formatting, it stays set.
public static void main(String[] args) {

    double price = 78.50;
    System.out.printf("The price is $%.2f", price); }


Final Variables

  • A final variable is a variable that cannot change after being assigned a value
  • To declare a constant, we use the keyword: final
    final int my_final = 1;
  • Note that we must assign a value when the final is declared


Magic Numbers

  • Imagine that you are a programmer hired to modify a payroll program
  • You come across the following section of code:
    double pay;
    pay = hours * 7.5 + (hours / 40)
          * (hours - 40) * 7.5 * 0.5;
    
  • The numbers are important to the program, but what do they mean?
  • Numbers like these are called Magic Numbers.
  • They are magic because the value or presence is unexplainable without more knowledge
    • Often, no one knows what they mean after 3 months, including the author
  • A programmer can often infer the meaning of numbers after reading the code carefully
  • A much better coding style is to use named final variables rather than literal numbers
  • For example:
    final double wage = 7.5;
    final double over_time_adder = 0.5;
    final int hours_per_week = 40;
    double pay;
    pay = hours * wage + (hours / hours_per_week)
          * (hours - hours_per_week) * wage * over_time_adder;
    
  • Now it is much easier to understand the code and see any problems or limitations in it
  • Another reason to use named final variables is that it is easier to change the value of the number
  • In the above example, we can easily change the wage without making errors in other parts of our code

More Information


Assignment Operators

  • As we discussed before, we assign values to variables using an equal (=) sign
    int sum = 0;
  • However, the equal sign is really an assignment operator and does not denote equality
  • Thus, unlike math, we can have the same variable on both sides of an equals sign:
    int sum = 25;    // initialize sum to 25
    sum = sum + 10;  // add to sum
    
  • Note that the value of the variable is changed in the second line
  • Reading variables from memory does not change them
  • Values placed into a variable replace (overwrite) previous values:


Shortcut Assignment Operators

  • We can use additional operators to calculate values and assign them to the variable on the left all in one statement
    • Known as shortcut assignment operators
  • The general syntax is:
    variable op= expression;
  • Where op is one of the five arithmetic operators: +-*/%
  • For example, the following two statements create the same result:
    x = x + 3;
    x += 3;
    
  • Shown below are the assignment operators with examples of how they are used:


Summary of Assignment Operators

Operator Description Example Equivalent To
= Assigns the value of the expression on the right to the variable on the left x = 3  
+= Adds the expression on the right to the variable on the left x += 3 x = x + 3
-= Subtracts the expression on the right from the variable on the left x -= 3 x = x - 3
*= Multiplies the expression on the right to the variable on the left and saves the result in the variable on the left x *= 3 x = x * 3
/= Divides the variable on the left by the expression on the right and saves the result in the variable on the left x /= 3 x = x / 3
%= Calculates the remainder from dividing variable on the left by the expression on the right and saves the result in the variable on the left x %= 3 x = x % 3



Increment and Decrement Operators

  • Adding or subtracting one is a common operation in programming
  • Java provides arithmetic shortcuts for these operations with the increment and decrement operators
  • The increment operator (++) adds 1 to a variable's value
  • Pre-increment adds 1 before evaluating an expression
    ++sum;
  • Post-increment evaluates the expression and then adds 1
    sum++;
  • The decrement operator works like the increments operator, except it subtracts 1 from the variable:
    --sum
    sum--
    
  • Pre- and post- increment matters when the operation is part of a larger expression
  • For example, consider the code:
    int x = 5;
    int y = x++;
    System.out.println("x=" + x + " y=" + y);
    
  • We may expect y to be 6 after this code executes
  • Instead, y has the value of 5
  • The reason is that ++ after a variable (post-increment) is equivalent to:
    y = x;
    x = x + 1;
    
  • On the other hand, ++ before a variable (pre-increment) is equivalent to:
    x = x + 1;
    y = x;
    


Casting

  • We often find ourselves converting one data type into another
  • This process is called type conversion or typecasting
  • Java is a strongly-typed language and checks for compatible data types both when compiling and while running
  • To put a value of a different type in a variable, you must convert the type
  • There are two types of conversion: implicit and explicit
  • The term for implicit conversion is sometimes called coercion
  • The most common form of explicit conversion is know as casting

Coercion

  • Type conversion is done automatically (implicitly) when a narrower-type is assigned to a broader-type:
    • Narrower means a smaller number of bytes
    • Broader means a larger number of bytes
  • Data type hierarchy (from narrowest to broadest):
    byte => short => int => long => float => double
                   
    
  • For example:
    double x;
    int n = 5;
    x = n;
    
  • Since n is an integer and x is a double, the value returned by n must be converted to type double before it is assigned to x
  • Note that casting only changes the type of an expression's returned value
    • Not the type of the variable
  • Thus the data type of variable n is unchanged -- it is still an int

Coercion in an Arithmetic Expression

  • Some arithmetic expressions have a mix of data types
  • All values implicitly cast to the highest level before the calculation
  • For example:
    double a;
    int n = 2;
    double y = 1.33;
    a = n / y;
    
  • n is automatically cast to type double before performing the arithmetic

Explicit Casting

  • Explicit casting changes the data type for a single use of the variable
  • To cast, precede the variable name with the new data type in parentheses:
    (typeName) variableName
    
  • Where:
    • typeName: one of the Java data types
    • variableName: the name of the variable
  • For example:
    int n;
    double x = 2.0;
    n = (int) x;
    
  • The value of x is converted from type double to int before assigning the value to n
  • Note that explicit casting is required to assign a broader type to a narrower type
  • ILLEGAL: Implicit casting to a lower data type:
    int n;
    double x = 2.1;
    n = x; // illegal in Java
    

    Illegal since x is double, n is an int, and double is a higher data type than int

  • LEGAL: Explicit casting to a lower data type:
    int n;
    double x = 2.1;
    n = (int) x; // legal in java
    
  • You can use an explicit cast even when an implicit one will be done automatically

Truncation When Casting double to Integer type

  • Converting (casting) a double to integer type does not round -- it truncates
  • The fractional part is lost (discarded, ignored, thrown away)
  • For example:
    int n;
    double x = 3.99999;
    n = (int) x; // x truncated
    
  • Value of n is 3

Activity 10.2: Prices (10pts)

  • Find a partner for pair programming
  • Open up Eclipse, create a new Java project named Price
  • Copy the following program into a class file named Price.java:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    
    public static void main(String[] args) {
        String name;
        double price = 0;
      Scanner input = new Scanner(System.in);

    System.out.print("Enter the product name: "); name = input.nextLine();
     
    System.out.print("Price of the " + name + ": "); price = input.nextDouble(); // Insert new statements here System.out.println("Total price: $" + price); }
  • Alter the block comments to include your name and section information to the top of the program.
  • Compile and run the starter program to make sure you entered it correctly.

    When you run the program, the output should look like this:

    Enter the product name: iPod Nano
    Price of the iPod Nano: 149.50
    Total price: $149.5
    

    Note the format of the numbers output for the total price. We will address this formatting issue later in the exercise.

  • Run the program again for a product with a very high cost, like a Boeing 777:
    Enter the product name: Boeing 777
    Price of the Boeing 777: 212345678
    Total price: $2.12345678E8
    

    Note the format of the numbers output for the total price. This format is called exponential notation. You may have encountered it in some of your math classes.

  • Let us correct the formatting of the total price. Alter the System.out statement that prints the total price:
    System.out.printf("Total price: $%.2f\n", price);
    
    Compile and run your program again and verify the output looks like:
    Enter the product name: Boeing 777
    Price of the Boeing 777: 212345678
    Total price: $212345678.00
    
  • Let us add a final variable that we will use later in our program. Enter the following code after the printf statement and before the statement that prints the total price:
    final int percent = 100;
    

    We are declaring this variable rather than using a magic number.

  • Now we will add sales tax to the price of the product. Enter the following code after the percent variable and before the statement that prints the total price:
    double taxRate = 0;
    System.out.print("Enter sales tax rate (%): ");
    taxRate = input.nextDouble();
    double tax = price * taxRate / percent;
    price += tax;
    

    Notice the last statement: price += tax;. This is an alternate way to code the statement: price = price + tax;.

  • Compile and run your modified program and verify the output looks like:
    Enter the product name: iPod nano
    Price of the iPod nano: 89.50
    Enter sales tax rate (%): 9.5
    Total price: $98.00
    
  • Now we will find the whole dollars and cents of the amount to demonstrate casting. Enter the following code after the statement that prints the total price and before the closing curly brace of main:
    int dollars = (int) price;
    System.out.println("In whole dollars: $" + dollars);
    

    Notice the (int) in the first statement. This is known as a type cast or just cast

  • Compile and run your modified program and verify the output looks like:
    Enter the product name: iPod nano
    Price of the iPod nano: 89.50
    Enter sales tax rate (%): 9.5
    Total price: $98.00
    In whole dollars: $98
    



Wrap Up

  • With your partner, answer the questions from today's learning objectives



Upcoming Assignments

~See You Thursday!~