java-foundations 20 min read

Boolean Expressions & Branching

The type that answers questions — and the control structures that act on the answers

Reading: Reges & Stepp: Ch. 4 §4.1–4.3

Part 1 — The boolean Type

boolean is Java’s fourth primitive type. It holds exactly one of two values: true or false.

boolean isRaining = true;
boolean hasTicket = false;
boolean isPassing  = 75 >= 60;   // evaluates to true

The third line is the pattern you use most: evaluate a comparison, store the result. Now isPassing holds the answer, and you can use it without repeating the condition:

// Without boolean variable — condition written twice
if (score >= 60) {
    System.out.println("Passing");
}
System.out.println("Is passing: " + (score >= 60));   // repeated!

// With boolean variable — condition evaluated once, result reused
boolean isPassing = score >= 60;
if (isPassing) {
    System.out.println("Passing");
}
System.out.println("Is passing: " + isPassing);   // clean

Key insight: Java requires a boolean expression inside if (...) — not an integer, not a String, not null. if (count) does not compile. if (count > 0) does. This is stricter than Python and C, and it prevents a whole class of bugs.


Part 2 — Comparison Operators

Every comparison returns boolean:

Operator Meaning Example Result
== equal to 5 == 5 true
!= not equal to 5 != 3 true
< less than 3 < 5 true
> greater than 5 > 3 true
<= less than or equal 5 <= 5 true
>= greater than or equal 4 >= 5 false
int score = 83;
boolean passingScore  = score >= 60;   // true
boolean perfectScore  = score == 100;  // false
boolean notPerfect    = score != 100;  // true

Part 3 — Logical Operators

Combine boolean expressions with &&, ||, !:

Operator Name Rule
&& AND true only if both sides are true
\|\| OR true if at least one side is true
! NOT flips true to false and false to true
int age = 20;
boolean hasID = true;

boolean canEnter    = age >= 18 && hasID;    // both must be true → true
boolean getsDiscount = age >= 65 || age < 12; // either condition → false
boolean needsID     = !hasID;                 // flip → false

Truth tables

A B A && B A || B
T T T T
T F F T
F T F T
F F F F

Short-circuit evaluation

Java stops evaluating as soon as the result is determined:

  • false && anythingfalse (right side never evaluated)
  • true || anythingtrue (right side never evaluated)

This matters when the right side has a side effect or could crash. Put the cheaper or “safety” check on the left.

// Safe: if s == null, the right side is never evaluated
if (s != null && s.equals("hello")) { ... }

Part 4 — Comparing Strings

Never use == to compare String content.

String grade = "A";

// WRONG: compares memory addresses, not content
if (grade == "A") { ... }   // might work sometimes, never rely on it

// CORRECT: compare characters
if (grade.equals("A")) {
    System.out.println("Excellent");
}

== on objects asks “are these the exact same object in memory?” — not “do they hold the same text?” Two separate String objects can contain identical text but be different objects.

Case-insensitive comparison

if (input.equalsIgnoreCase("YES")) { ... }   // matches "yes", "Yes", "YES"
Check Your Understanding
Which correctly tests whether grade holds the text "A"?
Agrade == "A"
Bgrade.equals("A")
Cgrade = "A"
Dgrade.compareTo("A")
Answer: B. == compares memory references, not content — unreliable for Strings. = is assignment, not comparison. compareTo returns an integer (0 if equal) — it requires an extra == 0 check. .equals() is the right tool.

Part 5 — if / if-else / if-else-if

if: run a block only when true

if (score >= 90) {
    System.out.println("Excellent");
}

If the condition is false, the block is skipped entirely.

if-else: choose one of two paths

if (score >= 60) {
    System.out.println("Passing");
} else {
    System.out.println("Not passing");
}

Exactly one branch runs — never both, never neither.

if-else-if: choose one of many paths

String grade;
if (score >= 90) {
    grade = "A";
} else if (score >= 80) {
    grade = "B";
} else if (score >= 70) {
    grade = "C";
} else if (score >= 60) {
    grade = "D";
} else {
    grade = "F";
}

Java checks conditions top to bottom and stops at the first true one. With score = 83:

  1. Is 83 ≥ 90? No.
  2. Is 83 ≥ 80? Yes.grade = "B". The rest is skipped.

Order matters: Put the more restrictive (higher threshold) condition first. If you check >= 80 before >= 90, a score of 95 would get “B” — because it passes >= 80 first and the chain stops there.

Always use braces

// Bug: looks like both lines are inside the if — only the first is
if (score >= 90)
    System.out.println("Excellent");
    System.out.println("A");    // ALWAYS runs — not part of the if

// Correct
if (score >= 90) {
    System.out.println("Excellent");
    System.out.println("A");
}

One-statement if bodies without braces are legal Java but cause bugs. Always include the braces.


Part 6 — Tracing Code by Hand

Before you can write branching code, read it. Substitute values and follow the logic step by step.

Trace with score = 75:

int score = 75;
String grade;

if (score >= 90) {
    grade = "A";
} else if (score >= 80) {
    grade = "B";
} else if (score >= 70) {
    grade = "C";
} else {
    grade = "F";
}

System.out.println("Grade: " + grade);
  1. Is 75 >= 90? No → skip
  2. Is 75 >= 80? No → skip
  3. Is 75 >= 70? Yesgrade = "C", chain done
  4. Prints: Grade: C
Trace yourself: what prints when score = 91?
  1. Is 91 >= 90? Yesgrade = "A", skip the rest.
  2. Prints: Grade: A

Part 7 — Lab 5 CP2 Pattern

int s1 = 88, s2 = 72, s3 = 95, s4 = 55, s5 = 87;

// Boolean variables — evaluate compound conditions once, store for reuse
boolean isHighest   = s3 >= s1 && s3 >= s2 && s3 >= s4 && s3 >= s5;
boolean isExcellent = s3 >= 90;
boolean isPassing   = s3 >= 60;

// Assign a letter grade
String grade;
if (s3 >= 90) {
    grade = "A";
} else if (s3 >= 80) {
    grade = "B";
} else if (s3 >= 70) {
    grade = "C";
} else {
    grade = "F";
}

// .equals() for String comparison — never ==
boolean isGradeA = grade.equals("A");

System.out.println("Grade: " + grade);
System.out.println("Excellent: " + isExcellent);
System.out.println("Is grade A: " + isGradeA);

Notice what each element tests:

  • boolean variables → CP2 test 1 (declares a boolean)
  • && in isHighest → CP2 test 2 (compound condition)
  • .equals("A") → CP2 test 3 (String comparison)
Check Your Understanding
What does this print when x = 15?
if (x > 10) {
    System.out.println("big");
} else if (x > 5) {
    System.out.println("medium");
} else {
    System.out.println("small");
}
Abig
Bmedium
Cbig and medium (both conditions are true)
Dsmall
Answer: A. 15 > 10 is true, so "big" prints and the chain is done. Even though 15 > 5 is also true, the else if is never reached — the first true branch wins.

What You Learned

  • boolean is a primitive type that holds true or false — declare variables with boolean name = expression
  • Comparison operators (==, !=, <, >, <=, >=) return boolean
  • && (AND), || (OR), ! (NOT) combine boolean values; short-circuit evaluation stops early
  • == compares memory references for objects — always use .equals() for String content comparison
  • if / if-else / if-else-if executes exactly one branch; top-to-bottom, first true wins
  • Always use braces {} even for single-line branches

What Comes Next

Next: type casting and floating-point precision — the full theory of why (double) forces decimal division, why 0.1 + 0.2 gives 0.30000000000000004, and how printf controls the output to hide the noise.