03 - Decision Making and Loops
A complete beginner-to-advanced guide to Java control flow, aligned with the Oracle Certified Professional: Java SE 21 Developer (1Z0-830) exam objectives.
Table of Contents
- What Is Control Flow?
- The
if/elseStatement - The Ternary Operator
- The
switchStatement switchExpressions (Java 14+)- Pattern Matching for
switch(Java 21) - Loops Overview
- The
forLoop - The Enhanced
forLoop - The
whileLoop - The
do-whileLoop breakandcontinue- Labels
- Certification Traps
- Common Mistakes
- Interview Questions
- Quick Revision Notes
- One-Page Cheat Sheet
1. What Is Control Flow?
Control flow is the order in which statements are executed. By default, code runs top to bottom — but decision-making and loops let you change that path.
+------------------+ +------------------+ +------------------+
| DECISIONS | | LOOPS | | JUMPS |
| if / else | | for | | break |
| switch | | while | | continue |
| ternary ?: | | do-while | | return |
+------------------+ +------------------+ +------------------+
2. The if / else Statement
The if statement runs a block only when a boolean condition is true.
Syntax Forms
// 1. simple if
if (age >= 18) {
System.out.println("Adult");
}
// 2. if-else
if (age >= 18) {
System.out.println("Adult");
} else {
System.out.println("Minor");
}
// 3. if-else-if ladder
if (score >= 90) {
grade = 'A';
} else if (score >= 80) {
grade = 'B';
} else {
grade = 'F';
}
Rules & Traps
| Rule | Detail |
|---|---|
Condition must be boolean | if (1) is a compile error (unlike C/C++). |
= vs == | if (x = true) works only for booleans; if (x = 5) fails for ints. |
| Braces optional for one statement | But omitting them is a common bug source. |
Dangling else | Binds to the nearest unmatched if. |
int x = 5;
// if (x = 10) { } // ERROR: int is not boolean
if (x == 10) { } // OK
boolean flag = false;
if (flag = true) { // legal but a BUG: assigns, doesn't compare
System.out.println("runs"); // this prints!
}
The Missing-Braces Trap
if (true)
System.out.println("A");
System.out.println("B"); // NOT part of the if! Always runs.
Both lines look indented, but only the first belongs to the if. "B" always prints.
3. The Ternary Operator
A compact if-else that produces a value.
String result = (age >= 18) ? "Adult" : "Minor";
// nested (use sparingly)
char grade = (score >= 90) ? 'A' : (score >= 80) ? 'B' : 'C';
Type Trap
Both branches must produce compatible types:
Object o = true ? "text" : 42; // OK: common type Object
// int x = true ? 1 : "two"; // ERROR: incompatible types
4. The switch Statement
switch selects one of many code blocks based on a value. Use it instead of long if-else-if ladders.
Classic (Colon) Syntax
int day = 3;
switch (day) {
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
default:
System.out.println("Other");
}
Allowed switch Types
| Allowed | Not Allowed |
|---|---|
byte, short, char, int | long |
String (Java 7+) | float, double |
enum | boolean |
Wrapper: Byte,Short,Character,Integer | objects (classic switch) |
Fall-Through (Critical Trap)
Without break, execution falls through to the next case:
int x = 1;
switch (x) {
case 1:
System.out.println("One"); // prints
case 2:
System.out.println("Two"); // ALSO prints (no break above)
break;
case 3:
System.out.println("Three");
}
// Output:
// One
// Two
Intentional Fall-Through (Grouping)
switch (day) {
case 6:
case 7:
System.out.println("Weekend");
break;
default:
System.out.println("Weekday");
}
Rules & Traps
| Rule | Detail |
|---|---|
case labels must be compile-time constants | No variables. final constants OK. |
No duplicate case values | Compile error. |
default is optional | Can be placed anywhere (runs if no case matches). |
case value must fit the switch type | case 300: for a byte switch = compile error. |
String switch | Uses .equals()/hashCode(); null selector → NPE. |
5. switch Expressions (Java 14+)
A switch expression returns a value and uses arrow (->) syntax — no fall-through, no break needed.
int day = 3;
String name = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
default -> "Other";
};
System.out.println(name); // Wednesday
Arrow vs Colon
| Feature | Colon (:) | Arrow (->) |
|---|---|---|
| Fall-through | Yes (needs break) | No (each case isolated) |
| Returns a value | Only via yield/assignment per case | Directly |
| Multiple labels | Stacked case 6: case 7: | case 6, 7 -> |
Multiple Labels & Blocks with yield
int day = 6;
String type = switch (day) {
case 1, 2, 3, 4, 5 -> "Weekday";
case 6, 7 -> "Weekend";
default -> {
// block body must use 'yield' to return a value
String msg = "Invalid";
yield msg;
}
};
Exhaustiveness (Key Rule)
A switch expression must be exhaustive — cover every possible value, or include a default.
enum Color { RED, GREEN, BLUE }
Color c = Color.RED;
// No default needed IF all enum constants are covered:
String hex = switch (c) {
case RED -> "#FF0000";
case GREEN -> "#00FF00";
case BLUE -> "#0000FF";
}; // exhaustive: compiles without default
If you omit a constant and have no default, it won't compile.
6. Pattern Matching for switch (Java 21)
Java 21 makes switch work on types and patterns, not just constants. This is a flagship exam topic.
Type Patterns
static String describe(Object obj) {
return switch (obj) {
case Integer i -> "int: " + i;
case String s -> "string of length " + s.length();
case Double d -> "double: " + d;
case null -> "null value";
default -> "unknown";
};
}
case nullis now allowed directly. Without it, anullselector throws NullPointerException.
Guarded Patterns (when)
A when clause adds a boolean condition to a pattern:
static String classify(Object obj) {
return switch (obj) {
case Integer i when i > 100 -> "big int";
case Integer i -> "small int";
case String s when s.isBlank() -> "blank string";
case String s -> "string: " + s;
default -> "other";
};
}
Record Patterns (Deconstruction)
record Point(int x, int y) {}
static String locate(Object obj) {
return switch (obj) {
case Point(int x, int y) when x == 0 && y == 0 -> "origin";
case Point(int x, int y) -> "point at " + x + "," + y;
default -> "not a point";
};
}
Pattern Matching Rules
| Rule | Detail |
|---|---|
| Order matters | More specific / guarded cases must come before general ones. |
| Dominance check | A subtype/guard case after a broader case = compile error (unreachable). |
null handling | Use case null; can combine case null, default ->. |
| Exhaustiveness | Required; usually needs a default (or covers a sealed hierarchy). |
| Type coverage | With sealed types, the compiler can verify exhaustiveness without default. |
// Dominance error example:
switch (obj) {
case Object o -> "any"; // too broad, first
// case String s -> "str"; // ERROR: unreachable (Object already matched)
}
7. Loops Overview
| Loop | Best For | Checks Condition |
|---|---|---|
for | Known number of iterations | Before each iteration |
Enhanced for | Iterating arrays/collections | Internally |
while | Unknown count, may run 0 times | Before each iteration |
do-while | Runs at least once | After each iteration |
for / while / for-each do-while
+----------------+ +----------------+
| check first | | run body |
| run body | | check after |
| (0+ times) | | (1+ times) |
+----------------+ +----------------+
8. The for Loop
for (int i = 0; i < 5; i++) {
System.out.println(i); // 0 1 2 3 4
}
Anatomy
for ( init ; condition ; update ) { body }
| | |
runs once checked runs after
at start each pass each pass
Variations
// multiple variables
for (int i = 0, j = 10; i < j; i++, j--) { }
// infinite loop (all parts optional)
for (;;) { break; }
// with var
for (var i = 0; i < 3; i++) { }
Scope Trap
for (int i = 0; i < 3; i++) { }
// System.out.println(i); // ERROR: i is out of scope here
9. The Enhanced for Loop
The for-each loop iterates over arrays and Iterable collections cleanly.
int[] nums = {10, 20, 30};
for (int n : nums) {
System.out.println(n);
}
List<String> names = List.of("Ann", "Bob");
for (String name : names) {
System.out.println(name);
}
Limitations (Traps)
| Limitation | Detail |
|---|---|
| No index access | You don't get the position; use a classic for if you need it. |
| Read-only of the variable | Reassigning the loop variable doesn't change the array/collection. |
| Cannot modify collection structure | Removing during for-each → ConcurrentModificationException. |
| Cannot iterate backwards | Only forward traversal. |
int[] arr = {1, 2, 3};
for (int x : arr) {
x = x * 2; // does NOT change arr — x is a copy
}
System.out.println(arr[0]); // 1 (unchanged)
10. The while Loop
Runs while a condition is true; may run zero times.
int i = 0;
while (i < 5) {
System.out.println(i);
i++;
}
Trap: Condition Must Be boolean
// while (1) { } // ERROR: int is not boolean
while (true) { break; } // OK: infinite loop with explicit exit
Trap: Unreachable Code
while (false) {
System.out.println("x"); // COMPILE ERROR: unreachable statement
}
while (false)is a compile error (unreachable body), butif (false)is not — the compiler treats them differently.
11. The do-while Loop
Runs the body first, then checks the condition — so it always runs at least once.
int i = 10;
do {
System.out.println(i); // prints 10 once
i++;
} while (i < 5); // false, but body already ran
Note the semicolon after
while (...)— required indo-while, forbidden after a normalwhileheader.
| Feature | while | do-while |
|---|---|---|
| Condition check | Before body | After body |
| Minimum runs | 0 | 1 |
Trailing ; | No | Yes (required) |
12. break and continue
| Keyword | Effect |
|---|---|
break | Exits the entire loop (or switch). |
continue | Skips to the next iteration. |
// break
for (int i = 0; i < 10; i++) {
if (i == 5) break; // stops at 5
System.out.print(i); // 01234
}
// continue
for (int i = 0; i < 5; i++) {
if (i % 2 == 0) continue; // skip even numbers
System.out.print(i); // 13
}
break in Nested Loops
A plain break only exits the innermost loop:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (j == 1) break; // breaks inner loop only
System.out.println(i + "," + j);
}
}
// prints 0,0 1,0 2,0
13. Labels
A label names a loop so break/continue can target an outer loop directly.
outer:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i + j == 2) {
break outer; // exits BOTH loops
}
System.out.println(i + "," + j);
}
}
// prints 0,0 0,1 1,0
continue with a Label
outer:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (j == 1) continue outer; // jump to next i
System.out.println(i + "," + j);
}
}
// prints 0,0 1,0 2,0
Label Rules
| Rule | Detail |
|---|---|
| Syntax | labelName: immediately before a loop (or block). |
break label; | Exits the labeled loop entirely. |
continue label; | Continues the labeled loop's next iteration. |
continue target | The label must be on a loop (not an arbitrary block). |
break target | Can be on any labeled block. |
14. Certification Traps
| # | Trap |
|---|---|
| 1 | if (x = 5) fails for ints; only booleans allow assignment in a condition. |
| 2 | Missing braces: only the next single statement belongs to the if. |
| 3 | Classic switch falls through without break. |
| 4 | switch does not accept long, float, double, or boolean. |
| 5 | case labels must be compile-time constants; no duplicates allowed. |
| 6 | String/wrapper switch with a null selector → NullPointerException. |
| 7 | switch expression must be exhaustive (cover all values or default). |
| 8 | Arrow switch has no fall-through; colon switch does. |
| 9 | A switch block returning a value needs yield (arrow blocks / colon style). |
| 10 | Java 21 pattern switch: case dominance/order errors are compile-time. |
| 11 | Pattern switch needs case null or it throws NPE on null. |
| 12 | while (false) {} = unreachable-code compile error; if (false) {} is fine. |
| 13 | for-each variable is a copy — modifying it doesn't change the source. |
| 14 | Loop variable in for (int i...) is out of scope after the loop. |
| 15 | do-while requires a trailing semicolon; plain while header does not. |
| 16 | continue label; must target a loop, not a plain block. |
15. Common Mistakes
| Mistake | Fix |
|---|---|
Forgetting break in classic switch | Add break or use arrow switch. |
Using = instead of == in conditions | Use == for comparison. |
Off-by-one in loop bounds (<= vs <) | Double-check boundaries. |
| Infinite loop (forgetting to update counter) | Ensure the condition can become false. |
| Modifying a collection during for-each | Use an Iterator or removeIf. |
Expecting do-while to skip when false initially | It always runs once. |
| Using broad pattern case before specific one | Put specific/guarded cases first. |
Trying switch on a double | Use if-else for floating-point. |
16. Interview Questions
Q1. What types can a classic switch work on?
byte, short, char, int, their wrappers, String, and enum. Not long, float, double, or boolean.
Q2. What is fall-through in a switch?
When a case has no break, execution continues into the next case(s) until a break or the end.
Q3. How do switch expressions differ from switch statements?
Expressions return a value, use -> (no fall-through), require exhaustiveness, and use yield for block bodies.
Q4. What is exhaustiveness in a switch expression?
Every possible input value must be handled — via covering all cases (e.g., all enum constants / sealed subtypes) or a default.
Q5. What is pattern matching for switch (Java 21)?
It lets case labels match types and deconstruct records, with optional when guards, instead of only matching constants.
Q6. Why is case null important in pattern switch?
Without it, a null selector throws NullPointerException; case null handles null safely.
Q7. Difference between break and continue?
break exits the loop entirely; continue skips to the next iteration.
Q8. What are labeled loops used for?
To break/continue an outer loop from within nested loops.
Q9. Difference between while and do-while?
while checks the condition first (0+ runs); do-while runs the body first (1+ runs).
Q10. Why does while(false){} not compile but if(false){} does?
The compiler flags the while body as unreachable code; if(false) is allowed (used historically for conditional compilation).
Q11. Can you modify an array element using a for-each loop? You can change object state, but reassigning the loop variable doesn't change the array — the variable is a copy of each element.
Q12. What is case dominance in pattern switch? A broader/earlier case that makes a later, more specific case unreachable — a compile-time error.
17. Quick Revision Notes
ifconditions must beboolean;=only works for booleans.- Single statement (no braces) — only that one line belongs to the
if. - Classic
switch: falls through withoutbreak; allowsint/char/String/enum, notlong/float/double/boolean. caselabels = compile-time constants, no duplicates.switchexpression:->, no fall-through, must be exhaustive,yieldfor blocks.- Java 21 pattern switch: type patterns,
whenguards, record deconstruction,case null; order/dominance matters. - Sealed types let the compiler verify exhaustiveness without
default. for,while, for-each: check condition first (0+ runs);do-while: runs at least once + needs trailing;.while(false){}= compile error;if(false){}is fine.- for-each variable is a copy; can't get index or remove during iteration.
break/continueaffect the innermost loop unless you use a label.- Loop variable scope ends with the loop.
18. One-Page Cheat Sheet
======================= DECISION MAKING & LOOPS CHEAT SHEET =======================
IF / ELSE
if (cond) {...} else if (cond) {...} else {...}
cond MUST be boolean ; if (x=5) -> ERROR (ints) ; missing braces = 1 stmt only
ternary: type r = cond ? a : b ; (a,b must be compatible types)
CLASSIC SWITCH (colon)
switch(x){ case 1: ...; break; default: ...; }
FALLS THROUGH without break
allowed: byte short char int + wrappers, String, enum
NOT allowed: long float double boolean
case = compile-time constant, no duplicates ; null String selector -> NPE
SWITCH EXPRESSION (arrow, Java 14+)
String s = switch(x){
case 1,2,3 -> "low";
case 4 -> { yield "four"; } // block needs yield
default -> "other";
};
NO fall-through ; MUST be exhaustive (all cases or default)
PATTERN MATCHING SWITCH (Java 21)
switch(obj){
case Integer i when i>100 -> "big";
case Integer i -> "int";
case String s -> s;
case Point(int x,int y) -> x+","+y; // record deconstruction
case null -> "null";
default -> "other";
}
specific/guarded cases FIRST ; dominance error = won't compile
no case null + null selector -> NPE
LOOPS
for(init;cond;update){...} // 0+ runs, check first
for(T x : iterable){...} // for-each; x is a COPY; no index
while(cond){...} // 0+ runs ; while(false){} = unreachable ERROR
do{...}while(cond); // 1+ runs ; TRAILING ; required
JUMPS
break; // exit innermost loop / switch
continue; // next iteration of innermost loop
break label; // exit labeled (outer) loop
continue label; // next iteration of labeled loop (must be a loop)
outer:
for(...) for(...) { break outer; } // exits both
==================================================================================
End of 03 - Decision Making and Loops.