The Stacks
UNIT 2: SELECTION AND ITERATION · TOPIC 2.5

2.5 Compound Boolean Expressions

Combine conditions with && and ||, negate with !. Short-circuit evaluation is the concept that turns into exam questions.

What you need to know

  • !a is true when a is false. a && b is true only when both are true. a || b is true when at least one is.
  • Precedence: ! first, then &&, then ||. Relational operators bind tighter than all three. Use parentheses to be safe.
  • Short-circuit evaluation: for a && b, if a is false, b is never evaluated. For a || b, if a is true, b is never evaluated.
  • Short-circuiting prevents errors: if (s != null && s.length() > 0) is safe because the length call is skipped when s is null. Reversed, it would crash.
  • Also prevents division by zero: if (d != 0 && n / d > 2).
  • Compound conditions can replace nested ifs: if (a) { if (b) { ... } } ≡ if (a && b) { ... } when there are no else branches.
  • !(x > 5) is x <= 5 — the negation includes the boundary.

Worked example

int age = 17;
boolean permit = true;
boolean canDrive = age >= 16 && permit;              // true
boolean discount = age < 13 || age >= 65;              // false
boolean neither = !(age < 13 || age >= 65);            // true

String s = null;
if (s != null && s.length() > 3)   // safe: second part skipped
{
    ...
}
Exam tip: For "which condition is safe" questions, the null or zero check must come first in an &&. For evaluation questions, compute each relational part to true/false, then apply ! → && → ||.

Going deeper

The nuance, edge cases, and connections that turn a 3 into a 5.

  • Precedence: ! (highest, unary) → && → || (lowest). And all three are below relational operators. a || b && c is a || (b && c).
  • Short-circuit is guaranteed, not optional. Java's && and || always skip the right operand when the left decides. This is what makes null-guards and zero-guards safe: x != null && x.method() never calls the method on null.
  • Order of the guard matters. s.length() > 0 && s != null is wrong — the length call happens first and crashes on null. Guard first, use second.
  • || short-circuits on true: x == 0 || 10 / x > 2 is safe because when x is 0, the division never runs.
  • Three or more operands: a && b && c is true only if all three are; evaluated left to right, stopping at the first false. a || b || c stops at the first true.
  • Compound conditions replace nested ifs when there are no elses. if (a && b) ≡ if (a) { if (b) … }. if (a || b) ≡ two separate ifs with the same body — except the body would run twice if both are true, so they're not quite equivalent.
  • !(a && b) is not !a && !b. It's !a || !b (2.6).

Mistakes that cost points

  • Guarding after using. arr[i] == 5 && i < arr.length crashes when i is out of bounds. Put the bound check first.
  • Misgrouping mixed && and ||. && binds tighter. Add parentheses mentally.
  • Thinking both sides always evaluate. They don't. The exam asks "does the method on the right ever get called" — and with short-circuit, the answer can be no.

Practice questions

Written in the style of the real exam. Try each one before revealing the answer.

Q1 For which values of x is x > 3 && x < 10 || x == 0 true?
  1. A Only x from 4 to 9
  2. B x from 4 to 9, or x equal to 0
  3. C Only x equal to 0
  4. D x from 3 to 10
Show answer

Answer: B. && binds tighter than ||: (x > 3 && x < 10) || x == 0. That's 4–9, or 0.

Q2 Consider if (arr.length > 0 && arr[0] == 5). Which best explains why this is safe even when arr has zero elements?
  1. A Java checks all array indices at compile time.
  2. B Because of short-circuit evaluation, arr[0] is never evaluated when arr.length > 0 is false.
  3. C arr[0] returns 0 for empty arrays.
  4. D The condition always evaluates both parts, so it is not safe.
Show answer

Answer: B. && stops as soon as the left side is false, so the out-of-bounds access never happens.

Key vocabulary

&& (and)
true only when both operands are true
|| (or)
true when at least one operand is true
! (not)
negates a boolean
Short-circuit evaluation
the right operand of && or || is skipped when the left operand decides the result