Series: Java Core for Beginners Lecture: 03 of 12 Topics: if/else · switch · for loop · while · do-while · break · continue · return
What Is Control Flow?
In the previous two lectures, every program you wrote executed in a straight line — one statement after another, top to bottom, every time. Real programs are rarely that simple. They need to make decisions, repeat actions, and skip over code depending on conditions.
Control flow is the order in which the JVM executes statements in your program. Control flow statements let you:
- Branch — execute different code depending on a condition (
if,switch) - Loop — repeat a block of code multiple times (
for,while,do-while) - Jump — exit a loop early or skip to the next iteration (
break,continue,return)
Mastering control flow is what transforms a list of instructions into a program that actually thinks.
if, else if, and else
The if statement is the most fundamental decision-making tool in Java. It evaluates a boolean expression and executes a block of code only if that expression is true.
Basic if
int temperature = 35;
if (temperature > 30) {
System.out.println("It's hot outside.");
}
The condition inside the parentheses must evaluate to a boolean. If temperature > 30 is true, the block runs. If it is false, the block is skipped entirely.
if-else
An else block runs when the if condition is false:
int score = 55;
if (score >= 60) {
System.out.println("Pass");
} else {
System.out.println("Fail");
}
Exactly one of the two blocks will execute — never both, never neither.
if-else if-else
Chain multiple conditions together with else if. Java evaluates them top to bottom and executes the first block whose condition is true:
int score = 78;
if (score >= 90) {
System.out.println("Grade: A");
} else if (score >= 80) {
System.out.println("Grade: B");
} else if (score >= 70) {
System.out.println("Grade: C");
} else if (score >= 60) {
System.out.println("Grade: D");
} else {
System.out.println("Grade: F");
}
// prints: Grade: C
Once a condition matches, the remaining else if and else blocks are skipped. The final else is a catch-all — it runs only if none of the preceding conditions were true. It is optional, but including it is good practice because it ensures your program handles every possible case explicitly.
Common mistakes with if statements
Mistake 1: Using = instead of ==
int x = 5;
if (x = 10) { } // COMPILE ERROR — assignment is not a boolean
if (x == 10) { } // correct
Mistake 2: Omitting curly braces
Java allows you to omit curly braces when an if body is a single statement:
if (score >= 60)
System.out.println("Pass"); // works
This is legal but risky. If you later add a second statement thinking it is inside the if, it will not be:
if (score >= 60)
System.out.println("Pass");
System.out.println("Congratulations!"); // always executes — NOT inside the if!
Always use curly braces, even for single-line bodies. This eliminates an entire class of bugs.
Mistake 3: Floating-point equality
Never use == to compare double or float values — floating-point arithmetic is imprecise:
double result = 0.1 + 0.2;
if (result == 0.3) { // false! result is 0.30000000000000004
System.out.println("Equal");
}
// Correct approach: check within a small tolerance (epsilon)
double epsilon = 1e-9;
if (Math.abs(result - 0.3) < epsilon) {
System.out.println("Equal"); // true
}
The Ternary Operator
The ternary operator is a compact form of if-else for simple value assignments. Its syntax is:
condition ? valueIfTrue : valueIfFalse
int age = 20;
String status = (age >= 18) ? "adult" : "minor";
System.out.println(status); // adult
int a = 15, b = 28;
int max = (a > b) ? a : b;
System.out.println(max); // 28
The ternary operator is an expression — it produces a value that can be stored in a variable, passed to a method, or embedded in a larger expression. Use it for simple, readable one-liners. When the logic becomes more complex, switch to a regular if-else for clarity.
switch Statement and switch Expression
When you need to compare a single variable against many specific values, a chain of else if statements works but becomes verbose. The switch construct handles this case more cleanly.
Traditional switch statement (all Java versions)
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;
case 4:
System.out.println("Thursday");
break;
case 5:
System.out.println("Friday");
break;
default:
System.out.println("Weekend");
}
// prints: Wednesday
Java evaluates the switch expression (day) and jumps to the matching case label. The default block runs if no case matches — it is optional but highly recommended.
The fall-through trap
The most dangerous aspect of the traditional switch statement is fall-through: if you omit a break, execution continues into the next case:
int day = 3;
switch (day) {
case 3:
System.out.println("Wednesday");
// no break!
case 4:
System.out.println("Thursday"); // also prints! fall-through
break;
case 5:
System.out.println("Friday");
}
// prints:
// Wednesday
// Thursday
Fall-through is occasionally useful (grouping cases together), but accidental fall-through is a very common bug. Always include break unless you deliberately intend fall-through — and leave a comment when you do.
Grouping cases intentionally:
switch (day) {
case 1:
case 2:
case 3:
case 4:
case 5:
System.out.println("Weekday");
break;
case 6:
case 7:
System.out.println("Weekend");
break;
}
switch works with these types
The switch expression can be: byte, short, int, char, String, or an enum. It cannot be long, double, float, or boolean.
Modern switch expression (Java 14+)
Java 14 introduced the switch expression with arrow syntax (->). It eliminates fall-through entirely, requires no break, and can produce a value:
int day = 3;
String dayName = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
case 6 -> "Saturday";
case 7 -> "Sunday";
default -> "Invalid day";
};
System.out.println(dayName); // Wednesday
Each case uses -> and executes exactly the expression on the right — no fall-through, no break needed. The result of the entire switch expression is assigned to dayName.
Multiple values can be grouped in a single case:
String type = switch (day) {
case 1, 2, 3, 4, 5 -> "Weekday";
case 6, 7 -> "Weekend";
default -> "Invalid";
};
For cases that need multiple statements, use a block with yield to produce the value:
String description = switch (day) {
case 1 -> "Monday";
case 6, 7 -> {
System.out.println("It's the weekend!");
yield "Weekend"; // yield returns a value from a block
}
default -> "Weekday";
};
Prefer the modern switch expression whenever you are on Java 14 or later. It is cleaner, safer, and more expressive than the traditional form.
The for Loop
A loop repeats a block of code multiple times. The for loop is the right choice when you know — or can calculate — exactly how many times you want to repeat.
Basic for loop
for (int i = 0; i < 5; i++) {
System.out.println("Iteration: " + i);
}
// prints: Iteration: 0
// Iteration: 1
// Iteration: 2
// Iteration: 3
// Iteration: 4
The for loop header has three parts separated by semicolons:
for (initialization ; condition ; update) {
// body
}
- Initialization (
int i = 0): runs once before the loop starts; declares and sets the loop variable - Condition (
i < 5): checked before each iteration; loop continues whiletrue - Update (
i++): runs after each iteration; typically increments the loop variable
The execution order is: initialization → condition check → body → update → condition check → body → update → … until the condition is false.
Loop variable conventions
By convention, loop variables are named i, j, k for simple counters. Use more descriptive names when the loop has semantic meaning:
for (int index = 0; index < array.length; index++) { }
for (int row = 0; row < rows; row++) { }
Counting down
for (int i = 10; i >= 1; i--) {
System.out.print(i + " ");
}
// prints: 10 9 8 7 6 5 4 3 2 1
Looping with a step other than 1
for (int i = 0; i <= 100; i += 10) {
System.out.print(i + " ");
}
// prints: 0 10 20 30 40 50 60 70 80 90 100
Iterating over arrays and strings
int[] scores = {85, 90, 72, 95, 88};
for (int i = 0; i < scores.length; i++) {
System.out.println("Score " + (i + 1) + ": " + scores[i]);
}
When you only need the values (not the index), the enhanced for loop (for-each) is simpler:
for (int score : scores) {
System.out.println(score);
}
Read this as: "for each score in scores". The loop variable score takes on each element in turn. You will use for-each constantly when working with collections in Lecture 8.
The while Loop
The while loop repeats as long as a condition remains true. Use it when you do not know in advance how many iterations you need — the loop continues until something changes.
Basic while loop
int count = 1;
while (count <= 5) {
System.out.println("Count: " + count);
count++;
}
// prints: Count: 1 through Count: 5
The condition is checked before each iteration. If the condition is false on the first check, the body never executes.
A realistic example
int number = 1;
while (number < 1000) {
number *= 2;
}
System.out.println(number); // 1024 — first power of 2 that exceeds 1000
Infinite loops and how to avoid them
An infinite loop runs forever because its condition never becomes false. This is almost always a bug:
int i = 0;
while (i < 10) {
System.out.println(i);
// forgot i++ — condition never becomes false
}
When writing a while loop, always ask: what changes on each iteration that will eventually make the condition false? If nothing changes, you have an infinite loop.
Occasionally, infinite loops are intentional — server programs that keep running until manually stopped. In those cases, use while (true) explicitly and rely on break to exit (covered in section 8).
while vs for
A mental model for choosing between them:
- Use
forwhen you have a counter or are iterating over a known sequence: "repeat exactly N times" or "iterate through this array" - Use
whilewhen you are waiting for a condition to change: "keep going until this becomes false"
// Natural fit for for: iterate 10 times
for (int i = 0; i < 10; i++) { }
// Natural fit for while: read until end of input
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
}
The do-while Loop
The do-while loop is like while, with one key difference: the body executes at least once because the condition is checked after the body, not before.
int number;
do {
System.out.print("Enter a positive number: ");
number = scanner.nextInt();
} while (number <= 0);
System.out.println("You entered: " + number);
This is the classic use case for do-while: input validation. You always need to read the input at least once before you can check whether it is valid. With a regular while, you would need to duplicate the input-reading code before the loop.
do-while syntax
do {
// body — always executes at least once
} while (condition); // semicolon required here
Note the semicolon after the closing parenthesis — it is required and a frequent source of compile errors for beginners.
When to use do-while
do-while is the least commonly used of the three loop types, but it has a clear niche: any situation where the loop body must run at least once before the condition can be meaningfully evaluated. Input validation and menu-driven programs are the canonical examples:
int choice;
do {
System.out.println("1. Start game");
System.out.println("2. Load game");
System.out.println("3. Quit");
System.out.print("Your choice: ");
choice = scanner.nextInt();
} while (choice < 1 || choice > 3);
break, continue, and return
These three keywords give you fine-grained control over what happens inside loops (and methods).
break
break immediately exits the innermost enclosing loop or switch statement. Execution continues with the first statement after the loop.
for (int i = 0; i < 10; i++) {
if (i == 5) {
break;
}
System.out.print(i + " ");
}
// prints: 0 1 2 3 4
A common use: searching for an element. Once found, there is no reason to continue iterating:
int[] numbers = {3, 7, 1, 9, 4, 6, 2};
int target = 9;
int foundAt = -1;
for (int i = 0; i < numbers.length; i++) {
if (numbers[i] == target) {
foundAt = i;
break; // stop searching once found
}
}
if (foundAt != -1) {
System.out.println("Found at index: " + foundAt); // Found at index: 3
} else {
System.out.println("Not found");
}
continue
continue skips the rest of the current iteration and jumps to the update step of a for loop (or back to the condition check of a while/do-while). The loop itself continues.
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
continue; // skip even numbers
}
System.out.print(i + " ");
}
// prints: 1 3 5 7 9
continue is useful for filtering — skipping elements that do not meet a criterion without deeply nesting the rest of the loop body.
break vs continue — the key distinction
break → exit the loop entirely
continue → skip this iteration, move to the next one
for (int i = 0; i < 5; i++) {
if (i == 3) break;
System.out.print(i + " ");
}
// 0 1 2 (stopped at 3)
for (int i = 0; i < 5; i++) {
if (i == 3) continue;
System.out.print(i + " ");
}
// 0 1 2 4 (skipped 3, continued to 4)
return
return exits the current method immediately, optionally returning a value to the caller. When used inside a loop, it exits both the loop and the method:
public static boolean containsNegative(int[] numbers) {
for (int n : numbers) {
if (n < 0) {
return true; // exits the method immediately
}
}
return false; // reached only if no negative was found
}
This pattern — returning early as soon as a result is known — is called a guard clause or early return. It avoids deeply nested logic and makes code easier to read.
A note on overusing break and continue
break and continue are legitimate tools, but overusing them inside complex nested loops can make code difficult to follow. If you find yourself reaching for them frequently, consider whether the loop can be restructured or extracted into a method.
Nested Loops
A loop can contain another loop inside it. The inner loop runs to completion for every single iteration of the outer loop.
Basic nested loop
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
System.out.print(i + "×" + j + "=" + (i * j) + " ");
}
System.out.println(); // new line after each row
}
Output:
1×1=1 1×2=2 1×3=3
2×1=2 2×2=4 2×3=6
3×1=3 3×2=6 3×3=9
Printing patterns
A classic exercise for nested loops is printing shapes:
// Right triangle of stars
int height = 5;
for (int row = 1; row <= height; row++) {
for (int col = 1; col <= row; col++) {
System.out.print("* ");
}
System.out.println();
}
Output:
*
* *
* * *
* * * *
* * * * *
break in nested loops only exits the innermost loop
outer: // label (optional, rarely needed)
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (j == 1) {
break; // exits only the inner loop
}
System.out.print(i + "," + j + " ");
}
}
// prints: 0,0 1,0 2,0
If you genuinely need to break out of an outer loop from inside an inner loop, Java supports labeled break:
outerLoop:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i == 1 && j == 1) {
break outerLoop; // exits the outer loop
}
System.out.print(i + "," + j + " ");
}
}
// prints: 0,0 0,1 0,2 1,0
Labeled break works, but use it sparingly. If you find yourself needing it often, consider extracting the nested loops into a separate method and using return instead.
Performance consideration
The total number of iterations in nested loops multiplies: a loop of N inside a loop of M runs N × M times. For N = M = 1000, that is 1,000,000 iterations. Be mindful of this when working with large data sets — nested loops are the most common cause of unexpectedly slow programs (quadratic time complexity, O(n²)).
Summary
Control flow is what makes your programs dynamic and responsive rather than fixed sequences of instructions.
if / else if / elsebranches execution based on boolean conditions. Always use curly braces and never use==for floating-point comparisons.- The ternary operator
? :is a compact single-expression alternative to simpleif-else. switchmatches a single variable against multiple values. The modern arrow-syntax switch expression (Java 14+) eliminates fall-through and is the preferred form.- The
forloop is ideal when the number of iterations is known. The enhanced for-each loop cleanly iterates over arrays and collections. - The
whileloop continues as long as a condition is true — the condition is checked before each iteration, so the body may never execute. - The
do-whileloop always executes the body at least once — the condition is checked after each iteration. Best for input validation. breakexits the innermost loop or switch.continueskips the current iteration.returnexits the entire method.- Nested loops multiply iteration counts.
breakonly exits the innermost loop by default; labeled break can exit an outer loop.
Exercises
Exercise 1 — Grade classifier Write a program that takes an integer score (0–100) and prints the corresponding letter grade (A/B/C/D/F) and a message ("Excellent!", "Good", "Satisfactory", "Passing", "Failing"). Use if-else if-else.
Exercise 2 — Day type with switch Write a program using the modern switch expression (arrow syntax) that takes an integer (1–7, where 1 = Monday) and prints whether it is a "Weekday" or "Weekend". Print an error message for any value outside 1–7.
Exercise 3 — Multiplication table Use nested for loops to print a 10×10 multiplication table. Align the columns neatly using String.format("%4d", value) so that each number occupies exactly 4 characters.
Exercise 4 — Sum of even numbers Use a while loop to compute the sum of all even numbers from 1 to 100. Then use a for loop with continue to achieve the same result. Verify both give the same answer (2550).
Exercise 5 — Validate input with do-while Simulate user input by writing a do-while loop that keeps prompting until a valid age is entered (between 0 and 120 inclusive). For this exercise, instead of real user input, iterate through a pre-defined array of test values: {-5, 200, 25} and pick the first valid one.
Exercise 6 — Prime number checker Write a method isPrime(int n) that returns true if n is a prime number and false otherwise. Use a for loop and break to exit early when a divisor is found. Then use it in a main method to print all prime numbers from 2 to 50.
Exercise 7 — Pattern printing Use nested loops to print the following pattern for a height of 5:
* * * * *
* * * *
* * *
* *
*
Up next: Lecture 4 — Classes & Objects — where Java's object-oriented nature takes center stage. You will learn how to design your own data types, create objects from them, and understand the relationship between a class and its instances.
