Control Flow in Java: if, else and switch
Decision making in Java, from the plain if statement to modern switch expressions and pattern matching.
-
Java Basics
- Introduction to Java
- Setting Up Java and Writing Your First Program
- Variables, Data Types and Literals in Java
- Type Casting and Type Conversion in Java
- Operators and Expressions in Java
- Input and Output in Java
- Comments, Keywords and Naming Conventions in Java
- Control Flow in Java: if, else and switch
- Loops in Java: for, while and do-while
- Methods
- Arrays and Strings
-
OOP
- Classes and Objects in Java
- Constructors in Java
- The this Keyword in Java
- The static Keyword in Java
- Encapsulation in Java
- Access Modifiers in Java
- Inheritance in Java
- Method Overriding and super in Java
- Polymorphism in Java
- Abstraction, Abstract Classes and Interfaces in Java
- Composition, Aggregation and Association in Java
- The Object Lifecycle in Java
- Core Java
- Exception Handling
-
Collections
- The Java Collections Framework
- List in Java: ArrayList, LinkedList, Vector and Stack
- Set in Java: HashSet, LinkedHashSet and TreeSet
- Map in Java: HashMap, LinkedHashMap and TreeMap
- How HashMap Works Internally in Java
- Queue and Deque in Java: ArrayDeque and PriorityQueue
- Iterators in Java
- Comparable and Comparator in Java
- Collections Utilities and Choosing the Right Collection
- Generics
- Java 8+
- Stream API
- Date and Time
- File and I/O
-
Multithreading
- Threads in Java: Processes, Runnable and Thread
- Thread Lifecycle in Java
- Synchronization in Java: synchronized and volatile
- Locks and Atomic Classes in Java
- Race Conditions and Deadlocks in Java
- The Executor Framework and Thread Pools in Java
- Future and CompletableFuture in Java
- Concurrent Collections in Java
- The Java Memory Model
- JVM and Memory
- Advanced Java
- Networking
- JDBC
- Testing
The if statement
int marks = 72;
if (marks >= 75) {
System.out.println("Distinction");
} else if (marks >= 50) {
System.out.println("Pass");
} else {
System.out.println("Fail");
}The condition must be a boolean. Java does not treat zero or null as false, which removes a whole family of bugs found in other languages.
Important rules
- An
elsebinds to the nearest unmatchedif. Braces make that explicit. - Only the first matching branch of an
if / else ifchain runs. - Assignment inside a condition is legal for
booleanvariables, which is exactly why=in place of==can slip through.
The conditional operator
String status = marks >= 50 ? "Pass" : "Fail";Use it when both branches produce a value for the same variable. Nesting it more than once makes code that is technically correct and practically unreadable.
The classic switch statement
int day = 3;
switch (day) {
case 1:
case 7:
System.out.println("Weekend");
break;
case 2:
case 3:
case 4:
case 5:
case 6:
System.out.println("Weekday");
break;
default:
System.out.println("Invalid day");
}Execution jumps to the matching label and then falls through every following label until a break or the end of the block. The grouped labels above use that deliberately; a forgotten break uses it accidentally.
Switch expressions
Java 14 finalised a form that produces a value, uses arrow labels and does not fall through.
String type = switch (day) {
case 1, 7 -> "Weekend";
case 2, 3, 4, 5, 6 -> "Weekday";
default -> "Invalid day";
};When a branch needs several statements, wrap it in a block and produce the result with yield:
int fee = switch (category) {
case "student" -> 100;
case "member" -> {
int base = 500;
yield base - discount;
}
default -> 800;
};A switch expression must be exhaustive. Over an enum that means covering every constant or supplying a default, and the compiler enforces it. This is a genuine advantage over the statement form.What switch accepts
| Type | Allowed |
|---|---|
byte short char int and their wrappers | Yes |
String | Yes, since Java 7 |
enum | Yes |
| Any reference type, using patterns | Yes, since Java 21 |
long, float, double, boolean | No |
Pattern matching for switch
Java 21 allows the selector to be matched against type patterns, which replaces long chains of instanceof tests.
static String describe(Object value) {
return switch (value) {
case null -> "nothing";
case Integer i when i < 0 -> "negative number " + i;
case Integer i -> "number " + i;
case String s -> "text of length " + s.length();
default -> "something else";
};
}The when clause adds a guard, and a matched variable such as i is already the right type inside its branch. Note that case null must be written explicitly; without it a null selector throws NullPointerException.
Common mistakes
- Omitting
breakin a classicswitchand processing more branches than intended. - Switching on a
Stringthat may benullwithout handling it. - Comparing strings in
ifwith==rather thanequals. - Deeply nested
ifblocks where an early return would read far better.
Best practices
- Always use braces, even for a single statement.
- Prefer the arrow form of
switchin new code; fall through is a source of bugs, not a feature. - Return early to keep the main path of a method flat.
- Order conditions so the common or cheap case is tested first.
Practice
- Convert the classic day
switchabove into a switch expression and explain whatbreakwas doing. - Predict the output when the
breakstatements are removed anddayis 3. - Write a method that returns a shipping charge for an enum
Zonewith valuesLOCAL,NATIONALandINTERNATIONAL, with nodefaultbranch. Why does that compile? - Rewrite a three level nested
ifof your own using early returns.
Conclusion
Branch on booleans, prefer the expression form of switch, and let the compiler check exhaustiveness for you. Modern control flow in Java is designed to make a missing case a compile error rather than a defect.