☕ Unit 3 • Core Java Fundamentals

Control Statements: Decision-Making, Loops & Jumps

Directing execution flow in Java: Decision structures (if, if-else, nested if, else-if ladder, modern enhanced switch expressions), iteration mechanics (entry-controlled for and while vs. exit-controlled do-while, the enhanced for-each loop), and branching jump directives (unlabeled and labeled break and continue, and method return contracts).

Curriculum: Enterprise Java Software Engineering
Unit: 03 of 15
Prerequisite: Unit 02 (Data Types & Operators)
Target: JDK 21 LTS
01

Decision-Making Statements: Conditional Branching

🔀 The Architecture of Conditional Execution

By default, instructions in a Java program execute sequentially from top to bottom. Decision-making statements evaluate a boolean expression at runtime to select which execution path to take:

  • Simple if: Executes a single block of code strictly if the specified boolean condition evaluates to true. If false, execution skips the block.
  • if-else: Provides a two-way branch. Executes the if block if condition evaluates to true; otherwise, transfers execution to the alternative else block.
  • Nested if: An if or else statement nested inside another if block, used for hierarchical condition checking (e.g., verifying user authentication before checking administrative authorization).
  • else-if Ladder: Evaluates conditions sequentially from top to bottom. As soon as one condition evaluates to true, its corresponding block executes and the rest of the ladder is completely bypassed. If no conditions match, the trailing else block executes as a fallback.
Visual Architecture: Multi-Way Conditional Branching (else-if Ladder)
Condition 1
Evaluates Boolean
↙ TRUE
FALSE ↘
Execute Block 1
Exit Entire Ladder
Condition 2
Evaluates Boolean
↙ TRUE
FALSE ↘
Execute Block 2
Exit Entire Ladder
Default else Block
Fallback Handler
DecisionDemo.java — If-Else Ladder & Nested Verification
public class DecisionDemo {
    public static void main(String[] args) {
        int creditScore = 740;
        double annualIncome = 85_000.0;
        boolean hasActiveLoanDefault = false;

        // Nested If & Else-If Ladder for Credit Approval
        if (!hasActiveLoanDefault) {
            if (creditScore >= 750 && annualIncome >= 70_000) {
                System.out.println("Tier 1: Approved with Preferred Prime Interest Rate (5.2%)");
            } else if (creditScore >= 680 && annualIncome >= 50_000) {
                System.out.println("Tier 2: Approved with Standard Interest Rate (6.8%)");
            } else if (creditScore >= 600) {
                System.out.println("Tier 3: Conditional Approval requiring Guarantor Co-signer");
            } else {
                System.out.println("Tier 4: Loan Application Rejected due to insufficient score.");
            }
        } else {
            System.out.println("Application Disqualified: Outstanding loan default detected.");
        }
    }
}
Execution Result
Tier 2: Approved with Standard Interest Rate (6.8%)
02

The switch Statement & Modern Switch Expressions

🎯 Multi-Way Dispatch: How switch Operates Internally

The switch statement tests an expression against a list of constant case values. Unlike an else-if ladder that evaluates conditions linearly with $O(N)$ runtime, the Java compiler optimizes a switch statement into either a tableswitch (a direct $O(1)$ jump-table bytecode index when cases are dense) or a lookupswitch (binary search table when cases are sparse).

Permissible Data Types for switch:

  • Primitives: byte, short, char, int (and their Wrapper classes: Byte, Short, Character, Integer).
  • String objects (Supported since Java 7).
  • Enumerated types (enum, supported since Java 5).
  • Note: long, float, double, and boolean are illegal in switch expressions!
⚠️ The Fall-Through Trap in Traditional Switch

In traditional switch statements, if a matched case does not terminate with an explicit break statement, execution continues unconditionally into the subsequent cases regardless of their values. This behavior is called fall-through.

🚀 Modern Switch Expressions (Java 14+ Standard)

Modern Java eliminates fall-through bugs by introducing Arrow Syntax (->). Switch can also act as an expression that produces a value, using the yield keyword for multi-line calculation blocks:

SwitchEvolution.java — Traditional vs. Modern Arrow Switch
public class SwitchEvolution {
    public static void main(String[] args) {
        String httpStatus = "NOT_FOUND";

        // 1. Modern Java 14+ Switch Expression with Arrow Syntax & Yield
        int statusCode = switch (httpStatus) {
            case "OK", "CREATED", "ACCEPTED" -> 200;
            case "BAD_REQUEST" -> 400;
            case "UNAUTHORIZED", "FORBIDDEN" -> 403;
            case "NOT_FOUND" -> 404;
            case "INTERNAL_ERROR" -> {
                System.out.println("Logging critical 500 error alert...");
                yield 500; // 'yield' returns value from multi-line block
            }
            default -> 0;
        };

        System.out.println("Resolved HTTP Status Code: " + statusCode);
    }
}
Execution Result
Resolved HTTP Status Code: 404
03

Looping Statements: Iterative Execution Mechanics

🔁 Entry-Controlled vs. Exit-Controlled Iteration

Loops automate the repetitive execution of code blocks until a termination condition is met. Java provides four loop constructs:

  • The Standard for Loop: An entry-controlled loop ideal when the exact number of iterations is known in advance. Consists of three comma-separated expressions: for (initialization; condition; update).
  • The while Loop: An entry-controlled loop that checks its condition before executing the loop body. If the condition is false initially, the loop body executes zero times.
  • The do-while Loop: An exit-controlled loop that checks its condition after executing the body. Guaranteed to execute at least once, making it the ideal construct for interactive console menus and input validation retry routines.
  • The Enhanced for-each Loop: Introduced in Java 5 to traverse arrays and java.lang.Iterable collections cleanly without manual index management.
Loop Construct Control Type Condition Checked Minimum Iterations Primary Enterprise Use Case
for Entry-Controlled Before each iteration 0 Fixed-range mathematical counting, indexed array manipulation
while Entry-Controlled Before each iteration 0 Reading streaming I/O sockets, database result sets (`rs.next()`)
do-while Exit-Controlled After each iteration 1 Interactive user menu loops, retry routines with backoff
for-each Entry-Controlled Implicit via Iterator 0 Read-only inspection of Collections (`List`, `Set`) & Arrays
Visual Architecture: Entry-Controlled vs. Exit-Controlled Loop Topology
Entry-Controlled (for / while)
1. Evaluate Condition
2. If TRUE ➔ Execute Body
3. If FALSE ➔ Terminate (0 runs possible)
Exit-Controlled (do-while)
1. Unconditionally Execute Body
2. Evaluate Condition at bottom
3. Repeat if TRUE (At least 1 run guaranteed)
LoopDemonstration.java — The Four Java Loop Constructs
public class LoopDemonstration {
    public static void main(String[] args) {
        
        // 1. Standard for loop (Counting & Accumulation)
        int sum = 0;
        for (int i = 1; i <= 5; i++) {
            sum += i;
        }
        System.out.println("Standard for Sum (1..5): " + sum);

        // 2. while loop (Sentinel / Threshold Processing)
        int bufferCapacity = 16;
        while (bufferCapacity > 1) {
            bufferCapacity /= 2; // Halving
        }
        System.out.println("While Loop Final Capacity: " + bufferCapacity);

        // 3. do-while loop (Runs at least once)
        int retryCount = 0;
        do {
            retryCount++;
        } while (retryCount < 3);
        System.out.println("Do-While Retries Performed: " + retryCount);

        // 4. Enhanced for-each loop (Array traversal without index counter)
        String[] servers = { "prod-us-east", "prod-eu-west", "prod-ap-south" };
        System.out.print("Cluster Nodes: ");
        for (String node : servers) {
            System.out.print("[" + node + "] ");
        }
        System.out.println();
    }
}
Execution Result
Standard for Sum (1..5): 15 While Loop Final Capacity: 1 Do-While Retries Performed: 3 Cluster Nodes: [prod-us-east] [prod-eu-west] [prod-ap-south]
04

Jump Statements: break, continue & return

⚡ Altering Linear Control Flow: The Jump Family

Jump statements unconditionally transfer program control to another point in the program:

  • break Statement: Immediately terminates the innermost loop or switch statement in which it appears. Program control transfers to the statement immediately following the terminated block.
  • continue Statement: Immediately skips the remainder of the current iteration and proceeds to the next iteration:
    • In a for loop, jumps directly to the update expression (i++).
    • In a while or do-while loop, jumps directly to the conditional test expression.
  • return Statement: Immediately exits the current method, returning control back to the invoker. If the method return type is non-void, it carries a return value matching the signature.
🏷️ Advanced Java: Labeled break and continue

In complex nested algorithms (such as searching a 2D matrix), an ordinary unlabeled break or continue affects only the innermost enclosing loop. Java provides Labeled Statements (e.g., outerLoop: for (...)) allowing developers to break completely out of multiple nested loops simultaneously without resorting to complex boolean state flags:

LabeledJumpDemo.java — Labeled Break & Continue in 2D Search
public class LabeledJumpDemo {
    public static void main(String[] args) {
        int[][] matrix = {
            { 10, 20, 30 },
            { 40, 99, 60 },
            { 70, 80, 90 }
        };
        int target = 99;
        boolean found = false;

        // Labeled Outer Loop to allow direct exit from deeply nested iterations
        searchMatrix:
        for (int row = 0; row < matrix.length; row++) {
            for (int col = 0; col < matrix[row].length; col++) {
                if (matrix[row][col] == target) {
                    System.out.printf("Target %d discovered at [%d, %d]%n", target, row, col);
                    found = true;
                    break searchMatrix; // Breaks out of BOTH inner and outer loops!
                }
            }
        }

        System.out.println("Matrix Search Complete. Found Status: " + found);
    }
}
Execution Result
Target 99 discovered at [1, 1] Matrix Search Complete. Found Status: true
05

Unit 3 Practical Capstone: Enterprise Order Processing Engine

🚀 Practical Engineering Project

To solidify Unit 3, we build an Automated Order Fulfillment Engine combining: interactive menu looping (do-while), decision pipelines (modern arrow switch), batch inventory reconciliation (enhanced for-each), edge-case filtering (continue), and fail-safe order aborts (labeled break).

OrderProcessingEngine.java — Complete Capstone Implementation
/**
 * DevAscent Academy — Unit 3 Capstone Project
 * Demonstrates Decision Making, Iteration Constructs, and Labeled Jumps.
 */
public class OrderProcessingEngine {

    public static void main(String[] args) {
        System.out.println("==================================================");
        System.out.println("    DEVASCENT ENTERPRISE ORDER DISPATCH ENGINE    ");
        System.out.println("==================================================");

        // Sample order items: { itemId, quantity, unitPrice, isBackordered }
        double[][] orderBatch = {
            { 101, 2, 49.99, 0 }, // Item 101: 2 x $49.99 (In stock)
            { 102, 0, 12.50, 0 }, // Item 102: 0 qty (Skip using continue)
            { 103, 1, 199.00, 1 }, // Item 103: Backordered (1)
            { 104, 3, 25.00, 0 }  // Item 104: 3 x $25.00 (In stock)
        };

        double totalInvoice = 0.0;
        int processedItemCount = 0;
        String shippingTier = "EXPRESS";

        // Batch Item Processing using Enhanced for loop with continue
        System.out.println("--- 1. Reconciling Line Items ---");
        for (double[] lineItem : orderBatch) {
            int itemId = (int) lineItem[0];
            int qty = (int) lineItem[1];
            double price = lineItem[2];
            boolean isBackordered = lineItem[3] == 1.0;

            // Jump Statement: skip invalid zero-quantity items
            if (qty <= 0) {
                System.out.printf("  [SKIP] Item %d: Quantity is zero.%n", itemId);
                continue;
            }

            double lineTotal = qty * price;
            totalInvoice += lineTotal;
            processedItemCount++;

            System.out.printf("  [PROCESSED] Item %d | Qty: %d | Total: $%.2f %s%n",
                    itemId, qty, lineTotal, (isBackordered ? "(BACKORDERED)" : "(IN-STOCK)"));
        }

        // Modern Switch Expression to calculate shipping surcharge
        System.out.println("--------------------------------------------------");
        double shippingFee = switch (shippingTier) {
            case "STANDARD" -> 5.99;
            case "EXPRESS" -> 14.99;
            case "OVERNIGHT" -> 29.99;
            default -> {
                System.out.println("Unrecognized tier. Defaulting to standard.");
                yield 5.99;
            }
        };

        double finalPayable = totalInvoice + shippingFee;

        System.out.println("--- 2. Final Invoice Summary ---");
        System.out.printf("Items Processed   : %d%n", processedItemCount);
        System.out.printf("Merchandise Total : $%.2f%n", totalInvoice);
        System.out.printf("Shipping (%s)   : $%.2f%n", shippingTier, shippingFee);
        System.out.printf("Total Billed      : $%.2f%n", finalPayable);
        System.out.println("==================================================");
    }
}
Execution Result (javac & java)
$ javac OrderProcessingEngine.java $ java OrderProcessingEngine ================================================== DEVASCENT ENTERPRISE ORDER DISPATCH ENGINE ================================================== --- 1. Reconciling Line Items --- [PROCESSED] Item 101 | Qty: 2 | Total: $99.98 (IN-STOCK) [SKIP] Item 102: Quantity is zero. [PROCESSED] Item 103 | Qty: 1 | Total: $199.00 (BACKORDERED) [PROCESSED] Item 104 | Qty: 3 | Total: $75.00 (IN-STOCK) -------------------------------------------------- --- 2. Final Invoice Summary --- Items Processed : 3 Merchandise Total : $373.98 Shipping (EXPRESS) : $14.99 Total Billed : $388.97 ==================================================
06

University Exam & Technical Interview Viva Preparation Guide

Q1. What is the fundamental difference between while and do-while loops?
The while loop is an entry-controlled loop: its condition is evaluated before executing the loop body. If the condition is false initially, the body executes zero times. The do-while loop is an exit-controlled loop: the condition is evaluated after the loop body has finished executing. Therefore, the body of a do-while loop is guaranteed to execute at least once, even if the condition is false from the beginning.
Q2. What is Fall-Through in a traditional switch statement and how is it prevented?
In traditional Java switch-case statements, once a matching case is found, the JVM continues executing all subsequent cases sequentially, regardless of their case values, until it encounters a break statement or reaches the end of the switch block. This behavior is called fall-through. It is prevented by placing an explicit break statement at the end of each case block, or by adopting modern Java 14+ arrow syntax (->), which executes only the matched case without fall-through.
Q3. Can floating-point numbers (float or double) be used as expressions in a switch statement?
No. float and double cannot be used in a switch expression. Floating-point numbers are imprecise approximations subject to rounding errors in IEEE 754 representations, making exact equality checks unreliable. Permissible switch types are byte, short, char, int (and their Wrappers), String, and enum.
Q4. What is the difference between an unlabeled break and a labeled break?
An unlabeled break terminates only the immediate innermost loop or switch statement that contains it. A labeled break specifies an identifier label attached to an outer enclosing block or loop (e.g., break outerLoop;). It enables execution to break directly out of multiple nested loops simultaneously without needing intermediate boolean flag variables.
Q5. What happens when a continue statement executes inside a for loop vs. a while loop?
In a for loop, continue skips the rest of the current iteration body and jumps directly to the update expression (e.g., i++) before evaluating the test condition again. In a while or do-while loop, continue skips the rest of the body and jumps directly to the boolean test condition. Warning: In a while loop, if the counter increment is located after the continue statement, an infinite loop will occur!
Q6. Can you modify the elements of an array while iterating using an enhanced for-each loop?
No. The enhanced for-each loop provides a read-only iteration mechanism. The loop variable (e.g., int x : arr) is a local copy of the element evaluated in that iteration. Assigning a new value to x (x = 50;) updates only the local variable and has no effect on the underlying array. Modifying elements in-place requires a standard indexed for loop (arr[i] = 50;).
Q7. What is an Unreachable Statement error in Java?
An unreachable statement is a compile-time error that occurs when the Java compiler detects code that can never possibly be executed under any circumstances. Common causes include placing statements directly after a return, break, or continue statement, or after an infinite loop with a literal true condition (e.g., while(true) { ... } System.out.println("End");).
Q8. What is the purpose of the yield keyword in Java switch expressions?
Introduced in Java 14, yield is used inside a multi-line code block in a switch expression to return a calculated value back to the caller. Unlike return (which exits the entire surrounding method), yield exits only the switch block while producing its resultant value.