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:
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 chainsif statementsswitch statement (traditional and enhanced)? :)Let us walk through each one with clear examples.
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.
if StatementThe 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.
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.
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.
if-else StatementThe 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.
if (condition) {
// runs when condition is true
} else {
// runs when condition is false
}
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.
if-else if-else ChainWhen 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.
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
}
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'.
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
if StatementsYou 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.
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 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 |
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.
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.
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:
case VALUE: (value first, then colon). A common mistake is writing case:VALUE with the colon before the value, which is a syntax error.break keyword exits the switch block. Without it, execution “falls through” into the next case.default case is optional but recommended. It handles any value not matched by a case.The switch expression supports: byte, short, int, char, String (Java 7+), and enum types. It does not support long, float, double, or boolean.
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.
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 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.
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:.
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.
| 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 |
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:
->) replaces the colon (:) and the break keyword.dayType.yield for Multi-Line Case BlocksWhen 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.
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...
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.
? :)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.
variable = (condition) ? valueIfTrue : valueIfFalse;
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.
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 |
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);
}
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.
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
}
if-else if chain for readability and (slight) performance gains.switch expressions (Java 14+) over traditional switch whenever possible. They are safer (no fall-through) and more concise..equals(), never with ==. The == operator compares object references, not the actual string content.if (isValid) reads better than if (!isInvalid).// 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);
}
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
| 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.