Java Conditional Statements

What Are Conditional Statements?

Conditional statements are the decision-making backbone of every Java program. They allow your code to evaluate a condition and execute different blocks of code depending on whether that condition is true or false.

Think of it like real life. You wake up and check the weather:

  • If it is raining, you grab an umbrella.
  • Else if it is cold but dry, you wear a jacket.
  • Else, you head out in a t-shirt.

Programming works the same way. Your code inspects a condition, and based on the result, it takes a specific path. Without conditional statements, every program would run the exact same instructions every time, which would make software pretty useless.

Java provides several tools for conditional logic:

  • if, if-else, and if-else if-else chains
  • Nested if statements
  • The switch statement (traditional and enhanced)
  • The ternary operator (? :)

Let us walk through each one with clear examples.

Comparison Operators Recap

Before we dive in, remember that conditions are built using comparison operators. These operators compare two values and return a boolean result (true or false).

Operator Meaning Example Result
== Equal to 5 == 5 true
!= Not equal to 5 != 3 true
> Greater than 10 > 7 true
< Less than 3 < 8 true
>= Greater than or equal to 5 >= 5 true
<= Less than or equal to 4 <= 9 true

For a deeper look at all Java operators, check out the Java Operators tutorial.

The if Statement

The if statement is the simplest form of conditional logic. It executes a block of code only when the condition evaluates to true. If the condition is false, the block is skipped entirely and execution continues after it.

Syntax

if (condition) {
    // code executes only when condition is true
}

Always use curly braces {}, even for single-line bodies. It prevents bugs when you later add more lines and improves readability.

Example: Checking if a Number is Positive

int temperature = 35;

if (temperature > 30) {
    System.out.println("It's a hot day! Stay hydrated.");
}

System.out.println("Have a great day!");

// Output:
// It's a hot day! Stay hydrated.
// Have a great day!

Here, temperature > 30 evaluates to true, so the message about staying hydrated is printed. The last line always prints regardless of the condition because it is outside the if block.

When to use: Use a standalone if when you only need to do something extra under a certain condition, and there is nothing special to do otherwise.

The if-else Statement

The if-else statement adds an alternative path. If the condition is true, the first block runs. If it is false, the else block runs instead. Exactly one of the two blocks will always execute.

Syntax

if (condition) {
    // runs when condition is true
} else {
    // runs when condition is false
}

Example: Checking Voting Eligibility

int age = 16;

if (age >= 18) {
    System.out.println("You are eligible to vote.");
} else {
    System.out.println("You are not eligible to vote yet.");
    int yearsLeft = 18 - age;
    System.out.println("You can vote in " + yearsLeft + " year(s).");
}

// Output:
// You are not eligible to vote yet.
// You can vote in 2 year(s).

Since age is 16, the condition age >= 18 is false, so Java skips the if block and executes the else block.

The if-else if-else Chain

When you have more than two possible outcomes, chain multiple conditions together using else if. Java evaluates each condition from top to bottom and executes the first block whose condition is true. If none match, the else block runs as a catch-all.

Syntax

if (condition1) {
    // runs if condition1 is true
} else if (condition2) {
    // runs if condition1 is false AND condition2 is true
} else if (condition3) {
    // runs if condition1 and condition2 are false AND condition3 is true
} else {
    // runs if none of the above conditions are true
}

Example 1: Grade Calculator

int score = 82;
char 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';
}

System.out.println("Score: " + score + " -> Grade: " + grade);

// Output:
// Score: 82 -> Grade: B

Key insight: The order of conditions matters. A score of 82 satisfies both score >= 70 and score >= 80, but because Java evaluates top to bottom and stops at the first match, it correctly assigns a 'B'. If you reversed the order and checked score >= 60 first, every passing score would get a 'D'.

Example 2: Age Group Classifier

int age = 30;
String ageGroup;

if (age < 0) {
    ageGroup = "Invalid age";
} else if (age < 13) {
    ageGroup = "Child";
} else if (age < 18) {
    ageGroup = "Teenager";
} else if (age < 30) {
    ageGroup = "Young Adult";
} else if (age < 60) {
    ageGroup = "Adult";
} else {
    ageGroup = "Senior";
}

System.out.println("Age: " + age + " -> Group: " + ageGroup);

// Output:
// Age: 30 -> Group: Adult

Nested if Statements

You can place an if statement inside another if statement. This is useful when a second decision only makes sense after a first condition is confirmed.

Example: Login Validation

String username = "admin";
String password = "secret123";
boolean isAccountLocked = false;

if (username.equals("admin")) {
    if (password.equals("secret123")) {
        if (!isAccountLocked) {
            System.out.println("Login successful! Welcome, admin.");
        } else {
            System.out.println("Account is locked. Contact support.");
        }
    } else {
        System.out.println("Incorrect password.");
    }
} else {
    System.out.println("User not found.");
}

// Output:
// Login successful! Welcome, admin.

A word of caution: Deeply nested if statements (3+ levels deep) become hard to read and maintain. When you find yourself nesting deeply, consider refactoring with guard clauses (covered in best practices below) or extracting logic into separate methods.

Logical Operators in Conditions

Logical operators let you combine multiple conditions into a single expression. This is often a cleaner alternative to nesting.

Operator Name Description Example
&& AND True if both conditions are true age > 18 && hasID
|| OR True if at least one condition is true isVIP || hasTicket
! NOT Reverses a boolean value !isBlocked

Example: Combining Conditions

int age = 25;
boolean hasLicense = true;
boolean isInsured = true;
boolean isSuspended = false;

// AND (&&) - all conditions must be true
if (age >= 16 && hasLicense && isInsured) {
    System.out.println("You can drive.");
}

// OR (||) - at least one must be true
boolean isWeekend = false;
boolean isHoliday = true;
if (isWeekend || isHoliday) {
    System.out.println("No work today!");
}

// NOT (!) - reverses the boolean
if (!isSuspended) {
    System.out.println("Your account is active.");
}

// Combining AND, OR, NOT
if ((age >= 18 && hasLicense) && !isSuspended) {
    System.out.println("Full driving privileges granted.");
}

// Output:
// You can drive.
// No work today!
// Your account is active.
// Full driving privileges granted.

Short-circuit evaluation: Java uses short-circuit evaluation with && and ||. With &&, if the first condition is false, Java does not evaluate the second condition because the overall result is already false. With ||, if the first condition is true, the second is skipped. This matters when the second condition has side effects or could throw an exception.

// Short-circuit prevents NullPointerException
String name = null;

// Safe: if name is null, the second condition is never evaluated
if (name != null && name.length() > 5) {
    System.out.println("Long name: " + name);
} else {
    System.out.println("Name is null or too short.");
}

// Output:
// Name is null or too short.

Traditional Switch Statement

The switch statement evaluates a single expression and matches it against a list of possible values (case labels). It is often a cleaner alternative to a long if-else if chain when you are comparing one variable against many known values.

Syntax

switch (expression) {
    case VALUE1:
        // code for VALUE1
        break;
    case VALUE2:
        // code for VALUE2
        break;
    case VALUE3:
        // code for VALUE3
        break;
    default:
        // code if no case matches
        break;
}

Important details:

  • The syntax is case VALUE: (value first, then colon). A common mistake is writing case:VALUE with the colon before the value, which is a syntax error.
  • The break keyword exits the switch block. Without it, execution “falls through” into the next case.
  • The default case is optional but recommended. It handles any value not matched by a case.

Supported Types

The switch expression supports: byte, short, int, char, String (Java 7+), and enum types. It does not support long, float, double, or boolean.

Example: Day of the Week

String day = "WEDNESDAY";

switch (day) {
    case "MONDAY":
        System.out.println("Start of the work week.");
        break;
    case "TUESDAY":
    case "WEDNESDAY":
    case "THURSDAY":
        System.out.println("Midweek - keep going!");
        break;
    case "FRIDAY":
        System.out.println("TGIF! Almost the weekend.");
        break;
    case "SATURDAY":
    case "SUNDAY":
        System.out.println("Weekend - time to relax!");
        break;
    default:
        System.out.println("Invalid day: " + day);
        break;
}

// Output:
// Midweek - keep going!

Notice how TUESDAY, WEDNESDAY, and THURSDAY share the same code block. Since there is no break after case "TUESDAY":, execution falls through to the next case. This is intentional fall-through and is a legitimate use of the behavior.

Example: Using switch with int

int month = 3;
String monthName;

switch (month) {
    case 1:
        monthName = "January";
        break;
    case 2:
        monthName = "February";
        break;
    case 3:
        monthName = "March";
        break;
    case 4:
        monthName = "April";
        break;
    case 5:
        monthName = "May";
        break;
    case 6:
        monthName = "June";
        break;
    case 7:
        monthName = "July";
        break;
    case 8:
        monthName = "August";
        break;
    case 9:
        monthName = "September";
        break;
    case 10:
        monthName = "October";
        break;
    case 11:
        monthName = "November";
        break;
    case 12:
        monthName = "December";
        break;
    default:
        monthName = "Invalid month";
        break;
}

System.out.println("Month " + month + " is " + monthName);

// Output:
// Month 3 is March

Fall-Through Behavior Explained

Fall-through is one of the most common sources of bugs in switch statements. If you forget a break, Java continues executing the next case’s code regardless of whether it matches.

// BUG: Missing break statements cause fall-through
int priority = 1;

switch (priority) {
    case 1:
        System.out.println("Critical");
        // missing break! Falls through to case 2
    case 2:
        System.out.println("High");
        // missing break! Falls through to case 3
    case 3:
        System.out.println("Medium");
        break;
    default:
        System.out.println("Low");
        break;
}

// Output (unintended!):
// Critical
// High
// Medium

Even though priority is 1, all three messages print because execution falls through from case 1 to case 2 to case 3 before hitting a break. This is why using break consistently is so important. The enhanced switch expression (covered next) eliminates this problem entirely.

Example: Using switch with enum

enum Season { SPRING, SUMMER, FALL, WINTER }

Season current = Season.SUMMER;

switch (current) {
    case SPRING:
        System.out.println("Flowers are blooming.");
        break;
    case SUMMER:
        System.out.println("Time for the beach!");
        break;
    case FALL:
        System.out.println("Leaves are changing color.");
        break;
    case WINTER:
        System.out.println("Bundle up, it's cold.");
        break;
}

// Output:
// Time for the beach!

Note: When using switch with enums, you do not prefix the enum name in the case labels. Write case SUMMER:, not case Season.SUMMER:.

Enhanced Switch Expression (Java 14+)

Java 14 introduced the switch expression as a standard feature (previewed in Java 12 and 13). It modernizes the switch with a cleaner syntax that eliminates fall-through bugs and allows the switch to return a value.

Key Differences from Traditional Switch

Feature Traditional Switch Enhanced Switch Expression
Syntax case VALUE: case VALUE ->
Fall-through Yes (requires break) No fall-through
Multiple labels Stacked cases Comma-separated: case A, B, C ->
Returns a value No Yes
break required Yes No

Arrow Syntax and Returning Values

import java.time.DayOfWeek;

DayOfWeek day = DayOfWeek.WEDNESDAY;

// Switch expression returns a value
String dayType = switch (day) {
    case MONDAY, TUESDAY           -> "Start of week";
    case WEDNESDAY, THURSDAY       -> "Midweek";
    case FRIDAY                    -> "End of work week";
    case SATURDAY, SUNDAY          -> "Weekend";
};

System.out.println(day + " is: " + dayType);

// Output:
// WEDNESDAY is: Midweek

Notice:

  • The arrow (->) replaces the colon (:) and the break keyword.
  • Multiple case labels are separated by commas instead of being stacked.
  • The entire switch is an expression that returns a value, assigned to dayType.
  • No fall-through is possible.

Using yield for Multi-Line Case Blocks

When a case needs to execute multiple lines of code before returning a value, wrap the code in a block {} and use the yield keyword to return the value.

int score = 85;

String result = switch (score / 10) {
    case 10, 9 -> "Excellent";
    case 8 -> {
        System.out.println("Processing grade B...");
        String detail = "Good job! You scored " + score;
        System.out.println(detail);
        yield "Good";  // 'yield' returns the value from this block
    }
    case 7 -> "Satisfactory";
    case 6 -> "Needs Improvement";
    default -> {
        System.out.println("Score below 60.");
        yield "Failing";
    }
};

System.out.println("Result: " + result);

// Output:
// Processing grade B...
// Good job! You scored 85
// Result: Good

The yield keyword works like return but specifically for switch expression blocks. You cannot use return inside a switch expression — return would exit the enclosing method, not the switch.

Enhanced Switch as a Statement (No Return Value)

You can also use the arrow syntax without returning a value. This gives you the cleaner syntax and no fall-through, even when you do not need to assign a result.

String command = "START";

// Arrow syntax used as a statement (no value returned)
switch (command) {
    case "START"   -> System.out.println("Starting the engine...");
    case "STOP"    -> System.out.println("Stopping the engine...");
    case "RESTART" -> {
        System.out.println("Stopping...");
        System.out.println("Starting...");
        System.out.println("Engine restarted.");
    }
    default        -> System.out.println("Unknown command: " + command);
}

// Output:
// Starting the engine...

Pattern Matching with Switch (Java 21+)

Java 21 introduced pattern matching for switch as a standard feature. This allows the switch to match against types (not just values), making it extremely powerful for handling polymorphic objects.

// Java 21+ Pattern Matching with switch
Object obj = "Hello, World!";

String description = switch (obj) {
    case Integer i when i > 0  -> "Positive integer: " + i;
    case Integer i             -> "Non-positive integer: " + i;
    case String s when s.isEmpty() -> "Empty string";
    case String s              -> "String of length " + s.length() + ": " + s;
    case Double d              -> "Double value: " + d;
    case null                  -> "It's null!";
    default                    -> "Unknown type: " + obj.getClass().getSimpleName();
};

System.out.println(description);

// Output:
// String of length 13: Hello, World!

Pattern matching with when guards lets you combine type checking and conditional logic in a single, readable expression. This replaces chains of instanceof checks followed by casting that were common in older Java code.

Ternary Operator (? :)

The ternary operator is a compact shorthand for a simple if-else that assigns a value. It is the only operator in Java that takes three operands.

Syntax

variable = (condition) ? valueIfTrue : valueIfFalse;

Examples

int age = 20;

// Ternary operator
String status = (age >= 18) ? "Adult" : "Minor";
System.out.println(status);
// Output: Adult

// Equivalent if-else
String status2;
if (age >= 18) {
    status2 = "Adult";
} else {
    status2 = "Minor";
}

// Ternary in method arguments
int a = 15, b = 22;
System.out.println("Max value: " + ((a > b) ? a : b));
// Output: Max value: 22

// Nested ternary (use sparingly - can hurt readability)
int score = 85;
String grade = (score >= 90) ? "A"
             : (score >= 80) ? "B"
             : (score >= 70) ? "C"
             : (score >= 60) ? "D"
             : "F";
System.out.println("Grade: " + grade);
// Output: Grade: B

Best practice: Use the ternary operator for simple, single-condition assignments. Avoid nesting ternary operators deeply — if the logic has more than two branches, use if-else if-else or a switch instead.

Best Practices

1. When to Use if-else vs switch

Scenario Use Why
Comparing a single variable against many known values switch Cleaner, more readable, better performance
Range-based conditions (>, <, >=) if-else Switch cannot do range comparisons
Complex boolean expressions if-else Switch evaluates a single expression
Two outcomes (true/false) if-else or ternary Switch is overkill for binary decisions
Type checking (Java 21+) switch with pattern matching Cleaner than instanceof chains

2. Avoid Deep Nesting

Deeply nested conditions are hard to read, test, and maintain. Aim for a maximum nesting depth of 2 levels.

// BAD: Deeply nested - hard to read
public void processOrder(Order order) {
    if (order != null) {
        if (order.isValid()) {
            if (order.hasStock()) {
                if (order.paymentApproved()) {
                    // finally do something useful
                    ship(order);
                } else {
                    System.out.println("Payment failed.");
                }
            } else {
                System.out.println("Out of stock.");
            }
        } else {
            System.out.println("Invalid order.");
        }
    } else {
        System.out.println("Order is null.");
    }
}

// GOOD: Guard clauses - flat and readable
public void processOrder(Order order) {
    if (order == null) {
        System.out.println("Order is null.");
        return;
    }
    if (!order.isValid()) {
        System.out.println("Invalid order.");
        return;
    }
    if (!order.hasStock()) {
        System.out.println("Out of stock.");
        return;
    }
    if (!order.paymentApproved()) {
        System.out.println("Payment failed.");
        return;
    }

    // Happy path - no nesting!
    ship(order);
}

3. The Guard Clause Pattern

A guard clause is an early return (or throw) that handles edge cases and invalid states at the top of a method. This keeps the main logic un-indented and easy to follow. As shown above, instead of wrapping everything in nested if blocks, check for failure conditions first and exit early.

4. Always Use Braces

Even for single-line if statements, always use curly braces. It prevents subtle bugs when you later add a second line to the block.

// BAD: No braces - easy to introduce bugs
if (isLoggedIn)
    System.out.println("Welcome!");
    loadDashboard(); // This ALWAYS runs! It is NOT inside the if.

// GOOD: Always use braces
if (isLoggedIn) {
    System.out.println("Welcome!");
    loadDashboard(); // Only runs when isLoggedIn is true
}

5. Additional Tips

  • Put the most likely condition first in an if-else if chain for readability and (slight) performance gains.
  • Use switch expressions (Java 14+) over traditional switch whenever possible. They are safer (no fall-through) and more concise.
  • Compare Strings with .equals(), never with ==. The == operator compares object references, not the actual string content.
  • Prefer positive conditions for readability. if (isValid) reads better than if (!isInvalid).
  • Extract complex conditions into well-named boolean variables to self-document your code.
// Hard to read
if (user.getAge() >= 18 && user.hasVerifiedEmail() && !user.isBanned() && user.getSubscription().isActive()) {
    grantAccess(user);
}

// Self-documenting with named booleans
boolean isAdult = user.getAge() >= 18;
boolean isVerified = user.hasVerifiedEmail();
boolean isInGoodStanding = !user.isBanned();
boolean hasActiveSubscription = user.getSubscription().isActive();

if (isAdult && isVerified && isInGoodStanding && hasActiveSubscription) {
    grantAccess(user);
}

Complete Runnable Example

Here is a complete program that demonstrates all the conditional statement types covered in this tutorial. You can copy this into your IDE and run it.

public class ConditionalStatements {

    public static void main(String[] args) {

        // --- 1. if statement ---
        int temperature = 35;
        if (temperature > 30) {
            System.out.println("1. It's hot outside!");
        }

        // --- 2. if-else ---
        int age = 16;
        if (age >= 18) {
            System.out.println("2. You can vote.");
        } else {
            System.out.println("2. You cannot vote yet. " + (18 - age) + " years to go.");
        }

        // --- 3. if-else if-else ---
        int score = 82;
        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";
        }
        System.out.println("3. Score " + score + " = Grade " + grade);

        // --- 4. Logical operators ---
        boolean hasLicense = true;
        boolean isInsured = true;
        if (age >= 16 && hasLicense && isInsured) {
            System.out.println("4. You can drive.");
        }

        // --- 5. Traditional switch ---
        String day = "FRIDAY";
        switch (day) {
            case "MONDAY":
            case "TUESDAY":
            case "WEDNESDAY":
            case "THURSDAY":
                System.out.println("5. Weekday");
                break;
            case "FRIDAY":
                System.out.println("5. TGIF!");
                break;
            case "SATURDAY":
            case "SUNDAY":
                System.out.println("5. Weekend!");
                break;
            default:
                System.out.println("5. Invalid day");
                break;
        }

        // --- 6. Enhanced switch expression (Java 14+) ---
        String dayType = switch (day) {
            case "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY" -> "Weekday";
            case "FRIDAY"    -> "Fri-yay!";
            case "SATURDAY", "SUNDAY" -> "Weekend";
            default -> "Unknown";
        };
        System.out.println("6. " + day + " is: " + dayType);

        // --- 7. Ternary operator ---
        String status = (age >= 18) ? "Adult" : "Minor";
        System.out.println("7. Age " + age + " = " + status);
    }
}

// Output:
// 1. It's hot outside!
// 2. You cannot vote yet. 2 years to go.
// 3. Score 82 = Grade B
// 4. You can drive.
// 5. TGIF!
// 6. FRIDAY is: Fri-yay!
// 7. Age 16 = Minor

Summary

Statement Use When
if You need to do something only when a condition is true
if-else You have two possible paths (true or false)
if-else if-else You have multiple conditions to check in sequence
Nested if A condition depends on another condition being true (use sparingly)
Traditional switch Comparing one variable against many fixed values (pre-Java 14)
Enhanced switch Same as above but cleaner, no fall-through, can return values (Java 14+)
Pattern matching switch Matching against types and complex patterns (Java 21+)
Ternary ? : Simple inline conditional assignment

Conditional statements are fundamental to every Java program. Master these patterns and you will be able to express any decision-making logic cleanly and correctly.




Subscribe To Our Newsletter
You will receive our latest post and tutorial.
Thank you for subscribing!

required
required


Leave a Reply

Your email address will not be published. Required fields are marked *