University College of Applied SciencesProgramming 1
العربية
Lecture 8 · 100 min

Many-Way Decisions

What does a program do when a question has more than two answers?

By the end of this lecture you will be able to

  1. Write an else-if chain and put its conditions in the right order
  2. Use nested conditions and tell which if each else belongs to
  3. Write switch with int, char and String, and control break and default
  4. Choose between if, switch and the ternary operator to suit the problem
  5. Build complete programs: a menu calculator, days in a month, leap years and a cash machine
In this lecture
  1. Many questions have more than two answers
  2. A chain runs the first branch whose condition is true, then skips the rest
  3. The order of conditions changes the result: start with the narrowest
  4. The word else is what ties conditions into one chain
  5. A final else guarantees the variable gets a value
  6. A nested if asks its question only after an earlier one succeeds
  7. else matches the nearest open if before it, whatever the indentation says
  8. Leap years: one rule that combines three conditions
  9. switch jumps to the case equal to the value
  10. Without break the program carries on into the next cases
  11. Deliberate fall-through groups several cases into one answer
  12. switch also works with char and String
  13. Use switch for exact values, and if for everything else
  14. The ternary operator picks between two values in one expression
  15. Final exercise: a menu calculator that brings it all together
  16. Review questions
Part one: else-if chains

Many questions have more than two answers

if-else chooses between only two roads. But a mark can mean A, B, C, D or F, and a lift button can mean any floor.

else-if chain

Questions in a row about ranges of values: is the mark 90 or more? If not, is it 80 or more?

Nested if

A question inside a question: is the code correct? If it is, is the balance enough?

switch

One question with exact values: which option did you press on the menu?

A chain runs the first branch whose condition is true, then skips the rest

Three answers from two conditions

Press "Debug line by line" and watch the conditions being checked from the top. Then try n = 5 and n = 0. Why does the last else need no condition?

public class Sign {
    public static void main(String[] args) {
        int n = -4;
        if (n > 0) {
            System.out.println("Positive");
        } else if (n < 0) {
            System.out.println("Negative");
        } else {
            System.out.println("Zero");
        }
    }
}
Output
Negative

The temperature is 25. More than one condition is true, so what does the program print?

public class Weather {
    public static void main(String[] args) {
        int temp = 25;
        if (temp > 30) {
            System.out.println("Hot");
        } else if (temp > 20) {
            System.out.println("Warm");
        } else if (temp > 10) {
            System.out.println("Mild");
        } else {
            System.out.println("Cold");
        }
    }
}
Show the output
Output
Warm

Why? temp > 10 is true too, but it is never even checked. As soon as the chain finds a true condition, it runs that branch and leaves.

The grade calculator

Enter 85, then 90, then 89. Notice the second condition needs no mark < 90: with a mark of 90 or more, the program would never reach it.

import java.util.Scanner;

public class GradeChain {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.print("Mark: ");
        int mark = input.nextInt();
        if (mark >= 90) {
            System.out.println("A");
        } else if (mark >= 80) {
            System.out.println("B");
        } else if (mark >= 70) {
            System.out.println("C");
        } else if (mark >= 60) {
            System.out.println("D");
        } else {
            System.out.println("F");
        }
    }
}

The order of conditions changes the result: start with the narrowest

An excellent mark, 95, but the conditions are in reverse order. What does it print?

public class WrongOrder {
    public static void main(String[] args) {
        int mark = 95;
        if (mark >= 60) {
            System.out.println("D");
        } else if (mark >= 70) {
            System.out.println("C");
        } else if (mark >= 80) {
            System.out.println("B");
        } else if (mark >= 90) {
            System.out.println("A");
        } else {
            System.out.println("F");
        }
    }
}
Show the output
Output
D

Why? 95 is more than 60, so the first condition is true and the chain ends. The program can never reach A, whatever the mark: every mark of 90 or more stops at the first condition. The compiler cannot catch this, because it is a logic error, not a writing error.

The correct grade calculator

Read a whole-number mark from 0 to 100, then print the grade: A from 90 up, B from 80, C from 70, D from 60 and F below that. Do not print a prompt.

import java.util.Scanner;

public class GradeCalculator {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        // Read the mark, then write the chain from highest to lowest

    }
}
stdin
100
Expected output
A
Hint 1

Start with the condition mark >= 90, then work your way down.

Hint 2

The last branch is else with no condition, and it prints F.

Solution
import java.util.Scanner;

public class GradeCalculator {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int mark = input.nextInt();
        if (mark >= 90) {
            System.out.println("A");
        } else if (mark >= 80) {
            System.out.println("B");
        } else if (mark >= 70) {
            System.out.println("C");
        } else if (mark >= 60) {
            System.out.println("D");
        } else {
            System.out.println("F");
        }
    }
}

The word else is what ties conditions into one chain

We removed the word else between the statements. What does the program print?

public class SeparateIfs {
    public static void main(String[] args) {
        int mark = 85;
        if (mark >= 90) {
            System.out.println("A");
        }
        if (mark >= 80) {
            System.out.println("B");
        }
        if (mark >= 70) {
            System.out.println("C");
        } else {
            System.out.println("F");
        }
    }
}
Show the output
Output
B
C

Why? These are three independent decisions, each checked regardless of the ones before. The last else belongs only to the if right before it, not to all the conditions.

When do you use several separate if statements instead of a chain?

A final else guarantees the variable gets a value

The compiler does not read logic

We know one of the two conditions is always true, but the compiler does not. Change the last branch to reassure it.

public class Result {
    public static void main(String[] args) {
        int mark = 70;
        String result;
        if (mark >= 60) {
            result = "Pass";
        } else if (mark < 60) {
            result = "Fail";
        }
        System.out.println(result);
    }
}
Compiler messagemight not have been initialized
Show the fix
public class Result {
    public static void main(String[] args) {
        int mark = 70;
        String result;
        if (mark >= 60) {
            result = "Pass";
        } else {
            result = "Fail";
        }
        System.out.println(result);
    }
}
Output
Pass

Why? The compiler does not weigh what the two conditions mean, so it sees a possible path where result gets no value. An else covers everything left, so no path remains without an assignment.

Part two: nested conditions

A nested if asks its question only after an earlier one succeeds

Cash machine: the code first, then the balance

Press "Debug line by line". Then change pin to 1111, then put it back and change amount to 500. Each wrong answer gets its own message, which one condition with && cannot give.

public class NestedAtm {
    public static void main(String[] args) {
        int pin = 1234;
        int balance = 300;
        int amount = 100;
        if (pin == 1234) {
            if (amount <= balance) {
                balance -= amount;
                System.out.println("Take your cash");
                System.out.println("Balance: " + balance);
            } else {
                System.out.println("Not enough balance");
            }
        } else {
            System.out.println("Wrong code");
        }
    }
}
Output
Take your cash
Balance: 200

A discount that depends on two questions

The purchase is 120 and the customer is a member. Try changing the input to 50 and no, then to 100 and no. Notice printf printing the amount to two decimal places.

import java.util.Scanner;

public class Discount {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        double total = input.nextDouble();
        String member = input.next();
        double rate;
        if (total >= 100) {
            if (member.equals("yes")) {
                rate = 0.20;
            } else {
                rate = 0.10;
            }
        } else {
            if (member.equals("yes")) {
                rate = 0.05;
            } else {
                rate = 0.0;
            }
        }
        System.out.printf("Pay: %.2f%n", total - total * rate);
    }
}
Output
Pay: 96.00

Cash machine withdrawal

The balance is a constant, 500. Read the amount to withdraw as a whole number and check in this order: if it is 0 or less print Invalid amount; if it is above the balance print Not enough balance; if it is not a multiple of 10 print Use multiples of 10. Otherwise print two lines: Take <amount>, then Balance: <remaining>. Do not print a prompt.

import java.util.Scanner;

public class Withdraw {
    public static void main(String[] args) {
        final int BALANCE = 500;
        Scanner input = new Scanner(System.in);
        // Read the amount, then check each case in order

    }
}
stdin
100
Expected output
Take 100
Balance: 400
Hint 1

A multiple leaves no remainder: amount % 10 != 0 means it is not a multiple of 10.

Hint 2

A constant cannot change, so print BALANCE - amount directly.

Solution
import java.util.Scanner;

public class Withdraw {
    public static void main(String[] args) {
        final int BALANCE = 500;
        Scanner input = new Scanner(System.in);
        int amount = input.nextInt();
        if (amount <= 0) {
            System.out.println("Invalid amount");
        } else if (amount > BALANCE) {
            System.out.println("Not enough balance");
        } else if (amount % 10 != 0) {
            System.out.println("Use multiples of 10");
        } else {
            System.out.println("Take " + amount);
            System.out.println("Balance: " + (BALANCE - amount));
        }
    }
}

else matches the nearest open if before it, whatever the indentation says

The else looks as if it belongs to the first condition. Does it? x is 5.

public class DanglingElse {
    public static void main(String[] args) {
        int x = 5;
        if (x > 0)
            if (x > 10)
                System.out.println("Big");
        else
            System.out.println("Not positive");
        System.out.println("End");
    }
}
Show the output
Output
Not positive
End

Why? The compiler ignores indentation and ties else to the nearest if before it, which is x > 10. 5 is positive but not above 10, so Not positive prints, which plainly means the wrong thing.

Braces settle the matter

The same program, but the braces tie else to the first condition. Press "Debug line by line", then try x = -2 and x = 20.

public class ElseWithBraces {
    public static void main(String[] args) {
        int x = 5;
        if (x > 0) {
            if (x > 10) {
                System.out.println("Big");
            }
        } else {
            System.out.println("Not positive");
        }
        System.out.println("End");
    }
}
Output
End

In the code above without braces: which if does else go with?

Leap years: one rule that combines three conditions

YearDivides by 4?Divides by 100?Divides by 400?Leap?
2024YesNoNoYes
2023NoNoNoNo
1900YesYesNoNo
2000YesYesYesYes

The rule: a year is a leap year if it divides by 4 and not by 100, or if it divides by 400.

Name each part of the condition

Boolean variables with clear names make a long condition readable. Try the four years in the table and follow the values with "Debug line by line".

public class LeapParts {
    public static void main(String[] args) {
        int year = 1900;
        boolean by4 = year % 4 == 0;
        boolean by100 = year % 100 == 0;
        boolean by400 = year % 400 == 0;
        System.out.println(by4);
        System.out.println(by100);
        System.out.println(by400);
        System.out.println((by4 && !by100) || by400);
    }
}
Output
true
true
false
false

Is it a leap year?

Read a year, then print Leap year if it is one, otherwise print Not a leap year. Do not print a prompt.

import java.util.Scanner;

public class LeapYear {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        // Read the year, then apply the rule

    }
}
stdin
2024
Expected output
Leap year
Hint 1

"Divides by 4" means year % 4 == 0.

Hint 2

(year % 4 == 0 && year % 100 != 0) || year % 400 == 0, and the parentheses make it clear.

Solution
import java.util.Scanner;

public class LeapYear {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int year = input.nextInt();
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
            System.out.println("Leap year");
        } else {
            System.out.println("Not a leap year");
        }
    }
}
Part three: switch and the ternary operator

switch jumps to the case equal to the value

switch (value) {
    case 1:
        // runs when value is 1
        break;      // leave the switch
    case 2:
        // runs when value is 2
        break;
    default:
        // runs when no case matches
}
Each case takes a fixed value and a colon, and the lines after it need no braces.

Name of the day

Day 1 is Sunday. Press "Debug line by line" to see the direct jump to case 3. Then try day = 9 to see default at work.

public class DayName {
    public static void main(String[] args) {
        int day = 3;
        switch (day) {
            case 1:
                System.out.println("Sunday");
                break;
            case 2:
                System.out.println("Monday");
                break;
            case 3:
                System.out.println("Tuesday");
                break;
            case 4:
                System.out.println("Wednesday");
                break;
            case 5:
                System.out.println("Thursday");
                break;
            default:
                System.out.println("Weekend or not a day");
        }
        System.out.println("Done");
    }
}
Output
Tuesday
Done

When does default run?

Without break the program carries on into the next cases

Look carefully at where break appears. n is 2. What does it print?

public class FallThrough {
    public static void main(String[] args) {
        int n = 2;
        switch (n) {
            case 1:
                System.out.println("One");
            case 2:
                System.out.println("Two");
            case 3:
                System.out.println("Three");
                break;
            case 4:
                System.out.println("Four");
            default:
                System.out.println("Other");
        }
    }
}
Show the output
Output
Two
Three

Why? The program jumps to case 2, then keeps moving down line by line without checking any other case until it hits break. This behaviour is called fall-through.

A wrong price from a missing break

Size 1 costs 5, yet the program prints 10. Press "Debug line by line" and watch price change three times. Then add break where it belongs so the program prints Price: 5.

public class SizePrice {
    public static void main(String[] args) {
        int size = 1;
        int price = 0;
        switch (size) {
            case 1:
                price = 5;
            case 2:
                price = 8;
            case 3:
                price = 10;
                break;
            default:
                price = 0;
        }
        System.out.println("Price: " + price);
    }
}
Output
Price: 10

Deliberate fall-through groups several cases into one answer

Days in the month

Seven months have 31 days. Stack their cases on top of each other, and they all fall to the same line. Press "Debug line by line", then change month to 1, then 2, then 13.

public class DaysInMonth {
    public static void main(String[] args) {
        int month = 4;
        int days;
        switch (month) {
            case 1: case 3: case 5: case 7:
            case 8: case 10: case 12:
                days = 31;
                break;
            case 4: case 6: case 9: case 11:
                days = 30;
                break;
            case 2:
                days = 28;
                break;
            default:
                days = 0;
        }
        System.out.println("Days: " + days);
    }
}
Output
Days: 30

Days in the month, leap years included

Read the month number, then the year. Print only the number of days in that month, with February having 29 days in a leap year. If the month is not from 1 to 12, print Invalid month. Do not print a prompt.

import java.util.Scanner;

public class MonthDays {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int month = input.nextInt();
        int year = input.nextInt();
        // Use switch on month; put the leap-year check under case 2

    }
}
stdin
1
2023
Expected output
31
Hint 1

Inside case 2: write an if-else using the leap-year rule, then break.

Hint 2

Put the error message in default, and print the number of days inside each case before break.

Solution
import java.util.Scanner;

public class MonthDays {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int month = input.nextInt();
        int year = input.nextInt();
        switch (month) {
            case 1: case 3: case 5: case 7:
            case 8: case 10: case 12:
                System.out.println(31);
                break;
            case 4: case 6: case 9: case 11:
                System.out.println(30);
                break;
            case 2:
                if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
                    System.out.println(29);
                } else {
                    System.out.println(28);
                }
                break;
            default:
                System.out.println("Invalid month");
        }
    }
}

switch also works with char and String

Describing a grade with char

A char value is written inside single quotes. Change grade to 'a', then to 'Z'. Notice how case 'A': case 'a': groups the capital and small letters.

public class GradeWords {
    public static void main(String[] args) {
        char grade = 'B';
        switch (grade) {
            case 'A': case 'a':
                System.out.println("Excellent");
                break;
            case 'B': case 'b':
                System.out.println("Very good");
                break;
            case 'C': case 'c':
                System.out.println("Good");
                break;
            default:
                System.out.println("Unknown grade");
        }
    }
}
Output
Very good

A text command from the user

switch works with String since Java 7, and it compares using equals, so it works with text read by Scanner. Change the input to stop, then to Start.

import java.util.Scanner;

public class Commands {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String command = input.next();
        switch (command) {
            case "start":
                System.out.println("Starting");
                break;
            case "stop":
                System.out.println("Stopping");
                break;
            default:
                System.out.println("Unknown command");
        }
    }
}
Output
Starting

The input is Yes with a capital letter. What does it print?

import java.util.Scanner;

public class Confirm {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String reply = input.next();
        switch (reply) {
            case "yes":
                System.out.println("Confirmed");
                break;
            case "no":
                System.out.println("Cancelled");
                break;
            default:
                System.out.println("Please answer yes or no");
        }
    }
}
Show the output
Output
Please answer yes or no

Why? switch on strings compares characters exactly, as equals does, and Yes is not yes.

Ticket price

Read the ticket type as one word and use switch: child costs 5, adult costs 10 and senior costs 7. Print Price: <price>, and for any other word print Unknown ticket. Do not print a prompt.

import java.util.Scanner;

public class Ticket {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String type = input.next();
        // Write the switch here

    }
}
stdin
child
Expected output
Price: 5
Hint 1

Do not forget break after each case, or the program prints several prices.

Hint 2

Strings in a case go inside double quotes: case "child":.

Solution
import java.util.Scanner;

public class Ticket {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String type = input.next();
        switch (type) {
            case "child":
                System.out.println("Price: 5");
                break;
            case "adult":
                System.out.println("Price: 10");
                break;
            case "senior":
                System.out.println("Price: 7");
                break;
            default:
                System.out.println("Unknown ticket");
        }
    }
}

Use switch for exact values, and if for everything else

SituationBest choiceWhy
A number from a menuswitchExact values of one variable
A grade from a markifRanges, not exact values
An age and a card togetherifMore than one variable
A double temperatureifswitch does not take double
A command character such as + or -switchExact char values

A condition where a value belongs

A case does not take a condition, only a fixed value. Rewrite the program with if-else so it prints A.

public class CaseRange {
    public static void main(String[] args) {
        int mark = 95;
        switch (mark) {
            case mark >= 90:
                System.out.println("A");
                break;
            default:
                System.out.println("Not A");
        }
    }
}
Compiler messageincompatible types: boolean cannot be converted to int
Show the fix
public class CaseRange {
    public static void main(String[] args) {
        int mark = 95;
        if (mark >= 90) {
            System.out.println("A");
        } else {
            System.out.println("Not A");
        }
    }
}
Output
A

Why? switch compares the int value mark with each case value. mark >= 90 is a boolean, so it cannot be compared with an int. That is why the message talks about types. Ranges are the job of if.

Two cases with the same value

The programmer meant the second case to print Friday for number 6. Fix the number.

public class DuplicateCase {
    public static void main(String[] args) {
        int day = 6;
        switch (day) {
            case 5:
                System.out.println("Thursday");
                break;
            case 5:
                System.out.println("Friday");
                break;
            default:
                System.out.println("Other");
        }
    }
}
Compiler messageduplicate case label
Show the fix
public class DuplicateCase {
    public static void main(String[] args) {
        int day = 6;
        switch (day) {
            case 5:
                System.out.println("Thursday");
                break;
            case 6:
                System.out.println("Friday");
                break;
            default:
                System.out.println("Other");
        }
    }
}
Output
Friday

Why? If the compiler allowed two equal cases, nobody could say which one the program jumps to. So every case value must be unique inside a switch.

Which problem does not suit switch?

The ternary operator picks between two values in one expression

result = condition ? valueIfTrue : valueIfFalse;
Read it as: is the condition true? If so, the first value; otherwise, the second.

One line instead of five

Change mark to 45 and predict the output. Then rewrite the third line with if-else and compare the two ways.

public class Ternary {
    public static void main(String[] args) {
        int mark = 72;
        int bonus = mark >= 70 ? 5 : 0;
        String result = mark >= 60 ? "Pass" : "Fail";
        System.out.println(result);
        System.out.println("Bonus: " + bonus);
    }
}
Output
Pass
Bonus: 5

It can go straight inside a print, in parentheses. What does this print?

public class TernaryPrint {
    public static void main(String[] args) {
        int x = 7;
        System.out.println(x + " is " + (x % 2 == 0 ? "even" : "odd"));
        int max = x > 10 ? x : 10;
        System.out.println(max);
    }
}
Show the output
Output
7 is odd
10

Why? 7 divided by 2 leaves 1, so the condition is false and we take "odd". In the second line 7 is not above 10, so we take 10.

Price by age

Read the age, then use the ternary operator to give price the value 5 if the age is under 12, otherwise 10. Print Price: <price>. Do not print a prompt.

import java.util.Scanner;

public class AgePrice {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int age = input.nextInt();
        // int price = ... ? ... : ...;

    }
}
stdin
5
Expected output
Price: 5
Hint 1

The condition is age < 12, and it comes before the ?.

Solution
import java.util.Scanner;

public class AgePrice {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int age = input.nextInt();
        int price = age < 12 ? 5 : 10;
        System.out.println("Price: " + price);
    }
}

Review questions

At most how many branches run in an if, else if, else chain?

What happens if you forget break in a case?

Which type does switch not accept in Java 8?

Predict: a chain, then a switch, then a ternary.

public class ReviewMixed {
    public static void main(String[] args) {
        int n = 15;
        if (n > 20) {
            System.out.println("High");
        } else if (n > 10) {
            System.out.println("Mid");
        } else {
            System.out.println("Low");
        }
        switch (n % 4) {
            case 3:
                System.out.println("Three");
            case 2:
                System.out.println("Two");
                break;
            default:
                System.out.println("Other");
        }
        System.out.println(n > 10 ? "Yes" : "No");
    }
}
Show the output
Output
Mid
Three
Two
Yes

Why? 15 is above 10 but not above 20, so Mid prints. 15 divided by 4 leaves 3, so the program jumps to case 3 and falls into case 2 up to break. Then the ternary prints Yes.