Learning goals
Write conditional branches, loops, and switch expressions; choose the right construct for each task; and avoid classic control-flow bugs (missing breaks, unreachable code, accidental fall-through).
if / else
int score = 85;
if (score >= 90) {
System.out.println("A");
} else if (score >= 80) {
System.out.println("B");
} else {
System.out.println("Below B");
}
Conditions must be boolean. No truthy/falsy like JavaScript:
// if (count) { } // compile error
if (count > 0) { }
switch — classic and modern
Switch expression (JDK 14+, preferred)
String day = "MON";
int hours = switch (day) {
case "MON", "TUE", "WED", "THU", "FRI" -> 8;
case "SAT", "SUN" -> 0;
default -> throw new IllegalArgumentException("Unknown: " + day);
};
->avoids fall-through; nobreakneeded.- Expression form returns a value (use
yieldin block cases if needed).
int code = switch (status) {
case "OK" -> 200;
case "ERROR" -> {
logError();
yield 500;
}
default -> 400;
};
Classic switch (legacy)
switch (day) {
case "MON":
System.out.println("Start week");
break; // required without ->
case "FRI":
System.out.println("Almost weekend");
break;
default:
System.out.println("Other");
}
Fall-through without break executes the next case—often a bug.
Switch supports String, primitives (int, char, byte, short), enums, and sealed types (with pattern matching in newer JDKs).
for loop
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
Enhanced for (for-each)—read-only over iterables/arrays:
int[] nums = {3, 1, 4};
for (int n : nums) {
System.out.println(n);
}
You cannot reassign the loop variable to change the array element’s slot semantics—use indexed for to mutate by index.
while and do-while
int n = 0;
while (n < 5) {
n++;
}
int m = 0;
do {
m++;
} while (m < 5);
do-while runs at least once. Use when the body must execute before the first check (e.g., menu prompts).
break and continue
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) continue; // skip evens
if (i > 10) break; // exit loop
System.out.println(i);
}
Labeled break (rare but useful for nested loops):
outer:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i * j > 2) break outer;
}
}
Pattern matching in switch (JDK 21 preview/stable features)
Be aware of evolving syntax for type patterns:
Object obj = "hello";
String result = switch (obj) {
case String s -> "String: " + s;
case Integer i -> "Integer: " + i;
case null -> "null";
default -> "other";
};
Guarded patterns (case String s when s.length() > 5) refine matching—read JDK release notes when upgrading.
return and early exit
Methods can return early to reduce nesting:
public String findUser(String id) {
if (id == null || id.isBlank()) {
return "unknown";
}
// main lookup logic
return lookup(id);
}
Common mistakes
- Assignment in condition:
if (x = 5)— use==. - Switch fall-through in classic
switchwithoutbreak. - Infinite loops:
while (true)without break, or forgetting to update loop variable. - Off-by-one:
i <= arr.lengthwhen indexing0..length-1. - Modifying collection while foreach-ing — causes
ConcurrentModificationException; use iterator.remove or collect then remove.
Practice checkpoint
-
Rewrite with switch expression: map
1..5to"one".."five", default"?".- Answer:
switch (n) { case 1 -> "one"; ... default -> "?"; }
- Answer:
-
Print first 5 odd numbers using a
whileloop.- Answer: Start
i=1, while count<5 print andi+=2.
- Answer: Start
-
What happens without
breakaftercase "A":in classic switch?- Answer: Execution falls through into the next case.
-
When prefer
do-whileoverwhile?- Answer: When body must run at least once before condition check.
Interview angles
- “switch on String—how?” — Compiler uses
hashCode/equalsinternally; null throws NPE. - “for vs enhanced for?” — Enhanced for is simpler and safe for read-only iteration; indexed for when you need index or mutation.
- “Can switch replace if-else chains?” — When matching discrete constants; if-else better for ranges and complex boolean logic.