03 - Decisions and Loops¶
What this session is¶
About an hour. You'll learn if/else/else if, the three loop forms (for, enhanced for, while), and modern Java's switch expressions - a much-improved version of the old switch statement.
Decisions: if / else¶
The world's smallest decision:
public class Age {
public static void main(String[] args) {
int age = 18;
if (age >= 18) {
System.out.println("adult");
} else {
System.out.println("minor");
}
}
}
What's new:
- if (condition) { ... } - the parentheses are required. Code in braces runs only when the condition is true.
- else { ... } - runs when the condition is false.
Java requires the braces. Some languages let you skip them for single-line bodies; Java doesn't, and that rule prevents a class of bugs. Always braces.
Comparison operators¶
| Operator | Meaning |
|---|---|
== |
equal to |
!= |
not equal to |
< |
less than |
<= |
less than or equal to |
> |
greater than |
>= |
greater than or equal to |
Important - strings: == compares references, not contents. To compare string contents, use .equals:
String a = "hello";
String b = "hello";
if (a == b) { ... } // might be true (or might not - undefined)
if (a.equals(b)) { ... } // always correct for content comparison
Always use .equals for strings. The "use == for primitives, .equals for objects" rule is one of the most-told Java beginner rules.
Chaining: else if¶
int score = 75;
if (score >= 90) {
System.out.println("A");
} else if (score >= 80) {
System.out.println("B");
} else if (score >= 70) {
System.out.println("C");
} else {
System.out.println("F");
}
First match wins, top to bottom. If none match, else runs.
Combining: &&, ||, !¶
| Operator | Meaning |
|---|---|
&& |
and (both true) |
\|\| |
or (at least one true) |
! |
not (flip) |
int age = 25;
boolean hasLicense = true;
if (age >= 18 && hasLicense) {
System.out.println("can drive");
}
Short-circuit: && doesn't evaluate the right side if the left is false. || doesn't evaluate the right if the left is true. Useful when the right side is expensive or might fail:
Repetition 1: for¶
The C-style for:
Three parts, separated by semicolons:
1. int i = 1 - runs once, before anything else.
2. i <= 5 - checked before each iteration; loop continues while true.
3. i++ - runs after each iteration. (Shorthand for i = i + 1.)
Output: 1, 2, 3, 4, 5.
The compact form. Useful when you need the index.
Repetition 2: enhanced for (for-each)¶
When iterating a collection or array, the enhanced form reads better:
String[] fruits = {"apple", "banana", "cherry"};
for (String fruit : fruits) {
System.out.println(fruit);
}
Read for (T x : collection) as "for each x in collection." Use this whenever you don't need the index.
Repetition 3: while¶
Keep going while the condition is true. The body must change something that affects the condition.
There's also do-while, which runs the body at least once before checking:
Rare; use when "do something once, then maybe repeat" is the natural shape.
Breaking out: break and continue¶
for (int i = 1; i <= 10; i++) {
if (i == 5) break; // stop the loop entirely
if (i % 2 == 0) continue; // skip to next iteration
System.out.println(i);
}
Output: 1, 3. (i=1 prints; i=2 even → skip; i=3 prints; i=4 even → skip; i=5 → break.)
Switch expressions: modern Java¶
Old switch (still works, has a famous fall-through bug):
switch (day) {
case 1: System.out.println("Mon"); break;
case 2: System.out.println("Tue"); break;
case 3: System.out.println("Wed"); break;
default: System.out.println("?");
}
The break is required - without it, execution "falls through" to the next case. Forgetting break is the canonical switch bug.
Modern Java (14+) has switch expressions with arrow syntax - no fall-through, no break required, returns a value:
int day = 2;
String name = switch (day) {
case 1 -> "Mon";
case 2 -> "Tue";
case 3 -> "Wed";
default -> "?";
};
System.out.println(name); // Tue
What's new:
- case 1 -> instead of case 1:. The arrow form doesn't fall through.
- The whole switch is an expression - produces a value you can assign or pass.
- The semicolon after the closing } (because the whole thing is one statement).
For multiple matching values:
String type = switch (day) {
case 1, 2, 3, 4, 5 -> "weekday";
case 6, 7 -> "weekend";
default -> "invalid";
};
For a block body (when one expression isn't enough), use yield:
String result = switch (input) {
case "a" -> "got a";
case "b" -> {
System.out.println("processing b");
yield "got b"; // yield is "return from this case"
}
default -> "unknown";
};
Always use the modern arrow form in new code. We'll see it heavily in page 08 when we meet pattern matching.
Exercise¶
In a new file Classify.java:
Write the classic FizzBuzz. For each number from 1 to 20:
- Divisible by 3 → print
Fizz. - Divisible by 5 → print
Buzz. - Divisible by both → print
FizzBuzz. - Otherwise → print the number.
Hint: check "both 3 and 5" first. Why? Think about what would happen if you checked "divisible by 3" first.
Expected output starts:
Don't move on until your program prints exactly the right thing.
Stretch: rewrite using a switch expression on n % 15. (15 = 3 × 5 - what values of n % 15 mean "divisible by 3 only", "by 5 only", "by both"?)
What you might wonder¶
"Why are parens required around if conditions?"
Java's grammar requires them. Python (if x > 0:) doesn't; Java does. Live with it.
"Why does == on strings sometimes work?"
Java interns string literals - identical literals share the same object, so "hello" == "hello" is true. But "hello" == new String("hello") is false (different objects, same content). Always use .equals to avoid this trap.
"Switch expression vs switch statement - when does the old form make sense?" Almost never in new code. The arrow form is shorter, safer (no fall-through), and produces a value. The only reason to use the old form is to integrate with very old codebases.
"What about pattern matching?"
Modern Java's switch can also match on types and destructure: case Point(int x, int y) -> .... We'll meet this in page 08 after we've learned classes.
Done¶
You can now:
- Make a program take different actions with if/else if/else.
- Use comparison and logical operators correctly.
- Know that .equals compares string contents; == is for primitives.
- Iterate with C-style for, enhanced for, and while.
- Use break and continue.
- Write modern switch expressions.
You have the core control flow. Next page: methods - Java's word for functions.