Control Flow & Loops

Logical Operators & Short-Circuiting

15 min Lesson 3 of 14

Logical Operators & Short-Circuiting

In the previous lesson you learned how to write if / else if / else blocks. Real programs almost always need to check more than one condition at a time — for example, "is the user logged in and old enough?" or "did the network fail or did the server return an error?". Java gives you three logical operators to combine boolean expressions: &&, ||, and !.

The AND Operator: &&

&& produces true only when both operands are true. Think of it as "this AND that must hold."

int age = 20; boolean hasTicket = true; if (age >= 18 && hasTicket) { System.out.println("Entry granted."); } else { System.out.println("Entry denied."); } // Output: Entry granted.

If either side is false, the whole expression is false. The truth table:

  • true && truetrue
  • true && falsefalse
  • false && truefalse
  • false && falsefalse

The OR Operator: ||

|| produces true when at least one operand is true. Think of it as "this OR that is enough."

boolean isAdmin = false; boolean isModerator = true; if (isAdmin || isModerator) { System.out.println("Access to dashboard granted."); } // Output: Access to dashboard granted.
  • true || truetrue
  • true || falsetrue
  • false || truetrue
  • false || falsefalse

The NOT Operator: !

! flips a boolean value. It is a unary operator — it takes only one operand and inverts it.

boolean isLoggedIn = false; if (!isLoggedIn) { System.out.println("Please log in first."); } // Output: Please log in first.
Tip — readability: Avoid double negation like if (!isNotEmpty). Rename the variable to isEmpty and write if (isEmpty). Code that reads like plain English is easier to maintain.

Short-Circuit Evaluation

This is one of the most important things to understand about && and ||. Java does not always evaluate both sides of a logical expression — it stops as soon as the result is determined.

  • With &&: if the left side is false, the result is already false, so the right side is skipped.
  • With ||: if the left side is true, the result is already true, so the right side is skipped.

This is not just an optimisation — it actively prevents errors. A classic example is guarding a null reference before using it:

String name = null; // Without short-circuit this would throw NullPointerException. // Because name == null is true, the right side is never reached. if (name == null || name.isEmpty()) { System.out.println("Name is blank."); } // Output: Name is blank.

If Java evaluated both sides regardless, name.isEmpty() would crash at runtime because name is null. Short-circuiting makes the guard pattern safe.

// Guarding array bounds before accessing an index int[] scores = {90, 85, 78}; int index = 5; if (index >= 0 && index < scores.length && scores[index] > 80) { System.out.println("High score at position " + index); } else { System.out.println("Index out of range or score not high."); } // Output: Index out of range or score not high. // scores[index] is never accessed because index < scores.length is false first.
Key idea: Always put the cheapest or safest check first. With &&, put the null/bounds guard on the left so the risky operation on the right is only reached when it is safe to do so.

Combining Multiple Operators

You can chain several logical operators in one expression. Java evaluates ! first, then &&, then || (standard precedence). Use parentheses to make your intent explicit and avoid surprises:

int temperature = 22; boolean isSunny = true; boolean isWeekend = false; // Is it a good day to go outside? boolean goodDay = isSunny && (temperature > 15) && !isWeekend; System.out.println("Good day to go out: " + goodDay); // Output: Good day to go out: false (isWeekend is false, !isWeekend is true — wait...) // Let's trace: isSunny=true, temperature>15=true, !isWeekend=!false=true => true // Output: Good day to go out: true
Common pitfall — operator precedence: a || b && c is parsed as a || (b && c) because && binds tighter than ||. When in doubt, add parentheses. They cost nothing and eliminate confusion.

Side Effects & Short-Circuiting

Because the right side may not run, avoid putting logic with side effects (like method calls that change state) inside a short-circuited condition unless you fully understand the implications:

int counter = 0; // The right side runs a method with a side effect. boolean result = false && (++counter > 0); System.out.println(counter); // 0 — counter was never incremented!

This is rarely what you want. Keep conditions pure — compare values, do not modify state inside them.

Summary

The three logical operators let you build precise, compound conditions. && requires both sides; || requires at least one side; ! flips a value. Short-circuit evaluation means the right operand is skipped when the result is already known — use this to guard null references and array bounds, and always place the safest check first.