Conditions: Programs That Choose
How does a program decide what to do based on the values it holds?
By the end of this lecture you will be able to
- Write conditions with relational operators and tell
=from== - Use
ifandif-elseto run one part of a program and not another - Explain what braces
{ }do and spot the semicolon trap after a condition - Combine conditions with
&&,||and!, and make use of short-circuiting - Check a range of values the right way and compare strings with
equals
In this lecture
- Programs choose, just as you do every day
- A condition is a question answered true or false
- if runs a block only when the condition is true
- = stores a value, == asks a question
- if-else always runs one of two branches, never both
- Braces decide what belongs to the condition, not indentation
- A semicolon after the condition makes the block always run
- &&, || and ! build one condition out of several
- ! comes first, then &&, then ||, and parentheses change that order
- Java stops as soon as it knows the answer, which guards us from dividing by zero
- Checking a range takes two comparisons joined by &&
- Compare strings with equals, not with ==
- Largest of two: store an answer in a variable, then correct it if needed
- Final exercise: a program that brings it all together
- Review questions
Programs choose, just as you do every day
Until now our programs ran every line from top to bottom, whatever the values were. Real programs look at the values first, then decide.
| Situation | The question | If the answer is yes | If the answer is no |
|---|---|---|---|
| Cash machine | Is the balance enough? | Hands you the money | Shows a refusal message |
| Unlocking a phone | Is the code correct? | Opens the screen | Asks for the code again |
| Exam result | Is the mark 60 or more? | Pass | Fail |
A condition is a question answered true or false
Relational operators produce a boolean, a type with only two values: true and false. You can print that value or store it in a variable like any other value.
| Operator | Meaning | Example | Result |
|---|---|---|---|
== | Equal to | 5 == 5 | true |
!= | Not equal to | 5 != 5 | false |
> | Greater than | 7 > 3 | true |
< | Less than | 7 < 3 | false |
>= | Greater than or equal to | 3 >= 3 | true |
<= | Less than or equal to | 4 <= 3 | false |
Ask Java six questions
Predict each line before running. Then change age to 18 and predict again.
public class Comparisons {
public static void main(String[] args) {
int age = 19;
System.out.println(age > 18);
System.out.println(age < 18);
System.out.println(age >= 19);
System.out.println(age <= 18);
System.out.println(age == 19);
System.out.println(age != 19);
boolean adult = age >= 18;
System.out.println(adult);
}
}true false true false true false true
Arithmetic comes before comparison. What does this print?
public class MathFirst {
public static void main(String[] args) {
int a = 7;
int b = 10;
System.out.println(a + 3 == b);
System.out.println(a % 2 == 0);
System.out.println(a * 2 > b);
}
}Show the output
true false true
Why? Java works out both sides of the comparison first: 10 equals 10, the remainder 1 is not 0, and 14 is greater than 10.
How do you write "x is not equal to zero" in Java?
! means "not" and comes straight before = with no space. Java has no <> operator, though other languages do.if runs a block only when the condition is true
if (condition) {
// runs only when the condition is true
}
// the program always continues here{ }.Watch the program skip a line
Press "Debug line by line" and watch which lines the program stops on. Then change temperature to 36 and step again: which line dropped out of the journey?
public class Temperature {
public static void main(String[] args) {
int temperature = 38;
if (temperature > 37) {
System.out.println("Fever: see a doctor");
}
System.out.println("Check finished");
}
}Fever: see a doctor Check finished
The balance is 40 and the price is 50. What does the program print?
public class Shop {
public static void main(String[] args) {
int balance = 40;
int price = 50;
if (balance >= price) {
System.out.println("Bought");
balance -= price;
}
System.out.println("Balance: " + balance);
}
}Show the output
Balance: 40
Why? The condition is false, so the program skips the whole block: neither the print nor the subtraction happens. The last line is outside the block, so it always runs.
= stores a value, == asks a question
Puts the value 5 in the box x.
x = 5;Asks: is the value of x equal to 5? The answer is true or false.
x == 5One sign short
Fix the condition so the program prints x is five.
public class CheckFive {
public static void main(String[] args) {
int x = 5;
if (x = 5) {
System.out.println("x is five");
}
}
}incompatible types: int cannot be converted to booleanShow the fix
public class CheckFive {
public static void main(String[] args) {
int x = 5;
if (x == 5) {
System.out.println("x is five");
}
}
}x is five
Why? The result of x = 5 is the value 5, an int, but if needs a boolean. The message talks about types and never mentions the missing sign, so remember this pattern when you see it inside a condition.
Here the compiler stays silent. What does the program print?
public class Finished {
public static void main(String[] args) {
boolean finished = false;
if (finished = true) {
System.out.println("Done");
}
System.out.println(finished);
}
}Show the output
Done true
Why? The condition is an assignment: it puts true in finished, and its result is the boolean true, so the compiler accepts it. That is why you write just if (finished) with boolean variables: then this slip cannot happen.
if-else always runs one of two branches, never both
Pass or fail?
Run it three times, entering 59, then 60, then 61: values at the boundary are the ones that reveal bugs. Then press "Debug line by line" to see which branch runs. Notice that we used a constant for the pass mark.
import java.util.Scanner;
public class PassFail {
public static void main(String[] args) {
final int PASS_MARK = 60;
Scanner input = new Scanner(System.in);
System.out.print("Mark: ");
int mark = input.nextInt();
if (mark >= PASS_MARK) {
System.out.println("Pass");
} else {
System.out.println("Fail");
}
System.out.println("Done");
}
}The first branch changes x. Does the program go back and check the condition?
public class OneBranch {
public static void main(String[] args) {
int x = 10;
if (x > 5) {
x = x - 8;
} else {
x = x + 8;
}
System.out.println(x);
}
}Show the output
2
Why? The condition is checked once only, before entering a branch. Yes, x is now 2, but the program does not return to the condition, and it skips the whole else.
Even or odd?
Read one whole number, then print Even if it is even and Odd if it is odd. Do not print a prompt.
import java.util.Scanner;
public class EvenOdd {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
// Read the number, then decide
}
}4
Even
Hint 1
An even number leaves no remainder when divided by 2: n % 2 == 0.
Hint 2
Do not write n % 2 == 1: in Java -3 % 2 is -1, so that condition goes wrong for negative numbers.
Solution
import java.util.Scanner;
public class EvenOdd {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
if (n % 2 == 0) {
System.out.println("Even");
} else {
System.out.println("Odd");
}
}
}Braces decide what belongs to the condition, not indentation
Both lines look as if they belong to the condition. Do they?
public class NoBraces {
public static void main(String[] args) {
int mark = 40;
if (mark >= 60)
System.out.println("Passed");
System.out.println("Well done");
System.out.println("End");
}
}Show the output
Well done End
Why? Without braces, only the one statement right after the condition belongs to it. The compiler ignores indentation completely: it is for human readers only. So Well done prints even for a failing mark.
Where did the if go?
The program wants to print two lines on a pass. Add what is missing.
public class TwoLines {
public static void main(String[] args) {
int mark = 75;
if (mark >= 60)
System.out.println("Passed");
System.out.println("Well done");
else
System.out.println("Failed");
}
}'else' without 'if'Show the fix
public class TwoLines {
public static void main(String[] args) {
int mark = 75;
if (mark >= 60) {
System.out.println("Passed");
System.out.println("Well done");
} else {
System.out.println("Failed");
}
}
}Passed Well done
Why? The if ended after the first line, so the second line became an ordinary statement and else found no if to follow. The message points at else, although the cause is the missing braces before it.
A variable that vanishes when the block ends
Declare result somewhere it stays known down to the print line.
public class BlockScope {
public static void main(String[] args) {
int mark = 75;
if (mark >= 60) {
String result = "Pass";
} else {
String result = "Fail";
}
System.out.println(result);
}
}cannot find symbolShow the fix
public class BlockScope {
public static void main(String[] args) {
int mark = 75;
String result;
if (mark >= 60) {
result = "Pass";
} else {
result = "Fail";
}
System.out.println(result);
}
}Pass
Why? A variable declared inside { } lives only inside them. Declare it before the block if you need it afterwards.
A semicolon after the condition makes the block always run
x is 3, so what is the output? Look closely at the end of the if line.
public class Semicolon {
public static void main(String[] args) {
int x = 3;
if (x > 5);
{
System.out.println("x is big");
}
System.out.println("End");
}
}Show the output
x is big End
Why? A lone semicolon is an empty statement that does nothing, and that empty statement is what the condition controls. The block after it stands on its own and always runs. The compiler does not object, because all of this is valid syntax.
See the trap with your own eyes
Press "Debug line by line": the condition is false, yet the program enters the block anyway. Then delete the semicolon after the condition and step through again.
public class VotingAge {
public static void main(String[] args) {
int age = 15;
if (age >= 18); {
System.out.println("You may vote");
}
}
}You may vote
The same slip, but now the compiler sees it
Having an else exposes the trap. Fix the line so the program prints Small.
public class BigSmall {
public static void main(String[] args) {
int x = 3;
if (x > 5); {
System.out.println("Big");
} else {
System.out.println("Small");
}
}
}'else' without 'if'Show the fix
public class BigSmall {
public static void main(String[] args) {
int x = 3;
if (x > 5) {
System.out.println("Big");
} else {
System.out.println("Small");
}
}
}Small
Why? The if ended at the semicolon, then a separate block followed, so else found no if to attach to. When you see this message, check the end of the if line first.
&&, || and ! build one condition out of several
&& (and)True only when both sides are true.
hasId && paidFees|| (or)True when at least one side is true.
isHoliday || isWeekend! (not)Flips the value: true becomes false, and the reverse.
!paidFeesa | b | a && b | a || b | !a |
|---|---|---|---|---|
true | true | true | true | false |
true | false | false | true | false |
false | true | false | true | true |
false | false | false | false | true |
The truth table in your own hands
Change hasId and paidFees through all four cases, predict the three results before each run, then compare with the table.
public class LogicTable {
public static void main(String[] args) {
boolean hasId = true;
boolean paidFees = false;
System.out.println(hasId && paidFees);
System.out.println(hasId || paidFees);
System.out.println(!paidFees);
}
}false true true
Two conditions in one if
A student enters the library if they have a card and have no late books. Change lateBooks to 2 and predict the output. Then use "Debug line by line" to see which branch runs.
public class Library {
public static void main(String[] args) {
boolean hasCard = true;
int lateBooks = 0;
if (hasCard && lateBooks == 0) {
System.out.println("Welcome");
} else {
System.out.println("Please see the librarian");
}
}
}Welcome
! comes first, then &&, then ||, and parentheses change that order
The first two lines differ only in their parentheses. What does the program print?
public class LogicOrder {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
boolean c = false;
System.out.println(a || b && c);
System.out.println((a || b) && c);
System.out.println(!a || b);
}
}Show the output
true false false
Why? In the first, && goes before ||, so b && c gives false, then true || false gives true. The parentheses in the second force || first, giving true && false. In the third, a is flipped first: false || false.
"Equals 6 or 7", the way we say it
We say it this way out loud, but Java wants a complete condition on each side of ||.
public class Weekend {
public static void main(String[] args) {
int day = 7;
if (day == 6 || 7) {
System.out.println("Weekend");
}
}
}bad operand types for binary operator '||'Show the fix
public class Weekend {
public static void main(String[] args) {
int day = 7;
if (day == 6 || day == 7) {
System.out.println("Weekend");
}
}
}Weekend
Why? The right side here is the number 7 alone, which is not a boolean, and || accepts only logical values. That is why the message mentions the types of the two sides.
Which condition means the same as !(x > 5)?
x < 5 is not enough.Java stops as soon as it knows the answer, which guards us from dividing by zero
| Expression | Left side | Is the right side evaluated? | Why |
|---|---|---|---|
a && b | false | No | The result is false whatever the right side is |
a && b | true | Yes | The result depends on it |
a || b | true | No | The result is true whatever the right side is |
a || b | false | Yes | The result depends on it |
The guard before the division
Run the program and see it work safely. Then swap the two sides of && so the condition reads total / students > 10 && students != 0 and run again: the program crashes with ArithmeticException: / by zero, because the division happened before the check.
public class GuardDivision {
public static void main(String[] args) {
int total = 90;
int students = 0;
if (students != 0 && total / students > 10) {
System.out.println("High average");
} else {
System.out.println("No high average");
}
}
}No high average
count is zero and the condition divides by it. What happens?
public class OrGuard {
public static void main(String[] args) {
int count = 0;
if (count == 0 || 10 / count > 1) {
System.out.println("Safe");
}
System.out.println("End");
}
}Show the output
Safe End
Why? The left side is true, which is enough to make || give true, so the division is never evaluated.
Which condition is safe when n is zero?
&&: when n is zero, the left side is false and the division is skipped. In the third option the left side is also false, but || then has to evaluate the right side, so the division happens.Checking a range takes two comparisons joined by &&
Mathematics is not Java
In mathematics we write 60 ≤ x ≤ 100. Fix the condition the Java way.
public class RangeCheck {
public static void main(String[] args) {
int mark = 75;
if (60 <= mark <= 100) {
System.out.println("Passing mark");
}
}
}bad operand types for binary operator '<='Show the fix
public class RangeCheck {
public static void main(String[] args) {
int mark = 75;
if (mark >= 60 && mark <= 100) {
System.out.println("Passing mark");
}
}
}Passing mark
Why? Java works from the left: 60 <= mark gives true, then it tries true <= 100, and comparing a boolean with a number means nothing. That is why the message names the types boolean and int.
The mark is 150, and the programmer used || instead of &&. What does it print?
public class WrongRange {
public static void main(String[] args) {
int mark = 150;
if (mark >= 0 || mark <= 100) {
System.out.println("Valid");
} else {
System.out.println("Invalid");
}
}
}Show the output
Valid
Why? Every number is either at least 0 or at most 100, so this condition is always true. Try values on and beyond the limits whenever you write a range condition.
A valid age
Read a whole-number age. Print Valid age if it is from 0 to 120, both included, otherwise print Invalid age. Do not print a prompt.
import java.util.Scanner;
public class ValidAge {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
// Read the age, then check the range
}
}19
Valid age
Hint 1
"Both included" means >= and <=, not > and <.
Hint 2
Use &&: both limits must hold together.
Solution
import java.util.Scanner;
public class ValidAge {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int age = input.nextInt();
if (age >= 0 && age <= 120) {
System.out.println("Valid age");
} else {
System.out.println("Invalid age");
}
}
}Compare strings with equals, not with ==
== with stringsAsks: do these two variables refer to the very same object in memory?
answer == "yes"equalsAsks: are the characters in the two strings the same? That is almost always what you want.
answer.equals("yes")A string from the keyboard
We gave the program the word yes as input. == prints false even though the characters match, because Scanner made a new string in another place in memory.
import java.util.Scanner;
public class CompareInput {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String answer = input.next();
System.out.println(answer == "yes");
System.out.println(answer.equals("yes"));
}
}false true
Three comparisons of strings with the same characters. What does the program print?
public class StringCompare {
public static void main(String[] args) {
String a = "java";
String b = "java";
String c = new String("java");
System.out.println(a == b);
System.out.println(a == c);
System.out.println(a.equals(c));
}
}Show the output
true false true
Why? Java makes identical string literals one shared object, so a == b gives true, while new makes a new object. That is why == seems right in small tests, then fails when the text comes from the user. So always use equals.
Letter case matters
The user typed YES. Notice the difference between equals and equalsIgnoreCase, then use ! to print Not yes when the strings do not match.
import java.util.Scanner;
public class IgnoreCase {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String answer = input.next();
System.out.println(answer.equals("yes"));
System.out.println(answer.equalsIgnoreCase("yes"));
}
}false true
The password
Read one word using next. Print Welcome if it is exactly java123, otherwise print Wrong password. Do not print a prompt.
import java.util.Scanner;
public class SecretWord {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
// Read the word, then compare it
}
}java123
Welcome
Hint 1
If only the first test fails, you are probably using ==.
Hint 2
password.equals("java123") gives a boolean you can put directly inside if.
Solution
import java.util.Scanner;
public class SecretWord {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String password = input.next();
if (password.equals("java123")) {
System.out.println("Welcome");
} else {
System.out.println("Wrong password");
}
}
}Largest of two: store an answer in a variable, then correct it if needed
Trace the variable max
Press "Debug line by line" and watch the box max. Then swap the values of a and b: is the result still right? Does the branch run this time?
public class Largest {
public static void main(String[] args) {
int a = 12;
int b = 30;
int max = a;
if (b > max) {
max = b;
}
System.out.println("Largest: " + max);
}
}Largest: 30
Largest of two
Read two whole numbers, then print only the larger one. If they are equal, print either. Do not print a prompt.
import java.util.Scanner;
public class LargestOfTwo {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
// Read two numbers and print the larger
}
}3 8
8
Hint 1
Do not start with max = 0, or your program fails with negative numbers.
Hint 2
Start with int max = a;, then use one if.
Solution
import java.util.Scanner;
public class LargestOfTwo {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int a = input.nextInt();
int b = input.nextInt();
int max = a;
if (b > max) {
max = b;
}
System.out.println(max);
}
}Final exercise: a program that brings it all together
May the student sit the exam?
Read the attendance percentage as a whole number, then the word yes or no saying whether the student paid the fees. Print Allowed if attendance is 75 or more and the word is yes, otherwise print Not allowed. Do not print a prompt.
import java.util.Scanner;
public class ExamEntry {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
// Read the attendance with nextInt and the word with next
}
}90 yes
Allowed
Hint 1
You need && joining a number comparison and equals.
Hint 2
The full condition: attendance >= 75 && paid.equals("yes").
Solution
import java.util.Scanner;
public class ExamEntry {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int attendance = input.nextInt();
String paid = input.next();
if (attendance >= 75 && paid.equals("yes")) {
System.out.println("Allowed");
} else {
System.out.println("Not allowed");
}
}
}Review questions
What is the difference between x = 5 and x == 5?
= changes the box; == asks about its contents without changing them, and gives a boolean.How do you check that x is between 1 and 10, both included?
true, while && requires both limits to hold together.Which condition checks that the string name is not Ali?
equals gives a boolean, and ! flips it. != compares where the objects are in memory, as == does, not their characters.Trace the conditions carefully: what does the program print?
public class ReviewCombo {
public static void main(String[] args) {
int x = 8;
if (x > 5 && x % 2 == 1) {
System.out.println("A");
} else {
System.out.println("B");
}
if (x > 10 || !(x == 3)) {
System.out.println("C");
}
System.out.println("D");
}
}Show the output
B C D
Why? 8 is even, so the first condition is false and B prints. In the second, x > 10 is false, but x is not 3, which is enough for ||, so C prints. D is outside every block.