☕ Java

switch Statement

The switch statement selects one of several code blocks to execute based on the value of a single expression. It is a cleaner alternative to a long if-else-if chain when choosing among multiple constant values. Java switch works with byte, short, int, char, String, and enum types. Each case label must be a compile-time constant and the optional default case handles all unmatched values.

Syntax and Basic Usage

The switch statement evaluates its expression once and jumps to the matching case label. Execution continues from that label until a break statement, a return, or the end of the switch block. The default label is optional and executes when no case matches — it can appear anywhere in the block, though placing it last is conventional.
Java
// ── Basic syntax: ────────────────────────────────────────────────────
//
//  switch (expression) {
//      case value1:
//          // statements
//          break;
//      case value2:
//          // statements
//          break;
//      default:
//          // statements when no case matches
//  }

// ── Day of week example: ─────────────────────────────────────────────
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");   // executes
        break;
    case 4:
        System.out.println("Thursday");
        break;
    case 5:
        System.out.println("Friday");
        break;
    case 6:
        System.out.println("Saturday");
        break;
    case 7:
        System.out.println("Sunday");
        break;
    default:
        System.out.println("Invalid day: " + day);
}

// ── Execution trace for day = 3: ─────────────────────────────────────
// 1. Evaluate expression: day = 3
// 2. Jump to case 3:
// 3. Print "Wednesday"
// 4. Hit break → exit switch
// 5. Continue after switch block

// ── default can appear anywhere — convention is last: ─────────────────
int code = 99;
switch (code) {
    default:
        System.out.println("Unknown code");   // executes
        break;
    case 1:
        System.out.println("Start");
        break;
    case 2:
        System.out.println("Stop");
        break;
}

Fall-Through Behaviour

When a case label is reached and there is no break statement, execution falls through to the next case and continues running its statements regardless of whether that case's label matches. Fall-through is sometimes used intentionally to share code between cases, but accidental fall-through is one of the most common Java bugs. Always use break unless fall-through is explicitly intended, and document it with a comment.
Java
// ── Accidental fall-through — common bug: ────────────────────────────
int value = 2;

switch (value) {
    case 1:
        System.out.println("One");
        // MISSING break — falls through to case 2!
    case 2:
        System.out.println("Two");
        // MISSING break — falls through to case 3!
    case 3:
        System.out.println("Three");
        break;
    case 4:
        System.out.println("Four");
        break;
}
// Output (value = 2):
// Two      ← case 2 matches
// Three    ← fell through from case 2 (no break)
// (stops at break in case 3)

// ── Intentional fall-through — multiple cases share code: ────────────
int month = 4;
int daysInMonth;

switch (month) {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
        daysInMonth = 31;       // intentional fall-through for 31-day months
        break;
    case 4:
    case 6:
    case 9:
    case 11:
        daysInMonth = 30;       // intentional fall-through for 30-day months
        break;
    case 2:
        daysInMonth = 28;       // simplified — ignoring leap years
        break;
    default:
        throw new IllegalArgumentException("Invalid month: " + month);
}
System.out.println("Days: " + daysInMonth);    // Days: 30

// ── Document intentional fall-through with @SuppressWarnings: ────────
switch (value) {
    case 1:
        System.out.println("Preprocessing...");
        // falls through intentionally
    case 2:
        System.out.println("Processing");      // runs for both 1 and 2
        break;
    default:
        System.out.println("Other");
}

switch with String and Enum

Java 7 added String support to switch. String comparison in switch uses equals() internally — it is case-sensitive. Enum switch is a natural fit since enum constants are compile-time constants. Both eliminate chains of if-else-if with equals() calls and produce cleaner, more readable code.
Java
// ── switch with String (Java 7+): ────────────────────────────────────
String direction = "NORTH";

switch (direction) {
    case "NORTH":
        System.out.println("Moving north");    // executes
        break;
    case "SOUTH":
        System.out.println("Moving south");
        break;
    case "EAST":
        System.out.println("Moving east");
        break;
    case "WEST":
        System.out.println("Moving west");
        break;
    default:
        System.out.println("Unknown direction: " + direction);
}

// ── String switch is case-sensitive: ─────────────────────────────────
String cmd = "quit";
switch (cmd.toLowerCase()) {     // normalise before switching
    case "start":
        startService();
        break;
    case "stop":
        stopService();
        break;
    case "quit":
    case "exit":
        System.out.println("Goodbye.");
        System.exit(0);
        break;
    default:
        System.out.println("Unknown command: " + cmd);
}

// ── switch with enum: ────────────────────────────────────────────────
enum Season { SPRING, SUMMER, AUTUMN, WINTER }

Season season = Season.SUMMER;

switch (season) {
    case SPRING:
        System.out.println("Flowers blooming");
        break;
    case SUMMER:
        System.out.println("Hot and sunny");        // executes
        break;
    case AUTUMN:
        System.out.println("Leaves falling");
        break;
    case WINTER:
        System.out.println("Cold and snowy");
        break;
    // No default needed — all enum constants covered.
    // Adding default is still good practice for safety.
}

// ── Returning from a method with switch: ─────────────────────────────
public static int getDaysInMonth(int month) {
    switch (month) {
        case 1: case 3: case 5: case 7:
        case 8: case 10: case 12:
            return 31;
        case 4: case 6: case 9: case 11:
            return 30;
        case 2:
            return 28;
        default:
            throw new IllegalArgumentException(
                "Invalid month: " + month);
    }
}

Supported Types and Restrictions

Switch expressions must be one of a specific set of types. Floating-point types (float, double), long, and boolean are not supported. Case labels must be compile-time constants — variables, method calls, and runtime values are not permitted as case labels. Understanding these restrictions prevents common compile errors.
Java
// ── Supported switch expression types: ──────────────────────────────
//
//  ✓  byte, short, int, char     (and their wrapper classes)
//  ✓  String                     (Java 7+)
//  ✓  enum types                 (all versions)
//  ✓  var (inferred as one of the above)
//
//  ✗  long      — not supported (use if-else or cast to int)
//  ✗  float     — not supported
//  ✗  double    — not supported
//  ✗  boolean   — not supported (use if-else)
//  ✗  Object    — not supported in traditional switch
//               (Java 21 pattern switch supports Object)

// ── Case labels must be compile-time constants: ───────────────────────
final int MAX = 100;         // compile-time constant (final + literal)
int       limit = 50;        // NOT a compile-time constant

int x = 75;
switch (x) {
    case 50:                 // ✓ integer literal
        break;
    case MAX:                // ✓ final variable with literal initialiser
        break;
    // case limit:           // ✗ COMPILE ERROR — not a compile-time constant
    // case x + 1:           // ✗ COMPILE ERROR — runtime expression
    // case getMax():        // ✗ COMPILE ERROR — method call
}

// ── Case labels must be unique: ───────────────────────────────────────
// switch (x) {
//     case 1:
//         break;
//     case 1:      // ✗ COMPILE ERROR — duplicate case label
//         break;
// }

// ── Null causes NullPointerException — switch does not handle null: ───
String s = null;
// switch (s) {   // ✗ throws NullPointerException at runtime
//     case "a": break;
// }

// Always null-check before switch:
if (s != null) {
    switch (s) {
        case "hello": System.out.println("Hi"); break;
        default: System.out.println("Other");
    }
}

// ── char in switch: ───────────────────────────────────────────────────
char grade = 'B';
switch (grade) {
    case 'A':
        System.out.println("Excellent");
        break;
    case 'B':
        System.out.println("Good");          // executes
        break;
    case 'C':
        System.out.println("Average");
        break;
    default:
        System.out.println("Below average");
}

Practical switch Patterns

These patterns show the most common real-world uses of the traditional switch statement — HTTP status handling, menu systems, state machines, and score classification. They also demonstrate when switch improves over if-else chains and when if-else remains the better choice.
Java
// ── HTTP status code handler: ────────────────────────────────────────
public String getStatusMessage(int statusCode) {
    switch (statusCode) {
        case 200: return "OK";
        case 201: return "Created";
        case 204: return "No Content";
        case 400: return "Bad Request";
        case 401: return "Unauthorized";
        case 403: return "Forbidden";
        case 404: return "Not Found";
        case 409: return "Conflict";
        case 500: return "Internal Server Error";
        case 503: return "Service Unavailable";
        default:  return "Unknown Status: " + statusCode;
    }
}

// ── Console menu: ────────────────────────────────────────────────────
Scanner scanner = new Scanner(System.in);
boolean running = true;

while (running) {
    System.out.println("
=== Menu ===");
    System.out.println("1. Add item");
    System.out.println("2. Remove item");
    System.out.println("3. List items");
    System.out.println("4. Exit");
    System.out.print("Choice: ");

    int choice = scanner.nextInt();

    switch (choice) {
        case 1:
            addItem();
            break;
        case 2:
            removeItem();
            break;
        case 3:
            listItems();
            break;
        case 4:
            running = false;
            System.out.println("Goodbye.");
            break;
        default:
            System.out.println("Invalid choice. Enter 14.");
    }
}

// ── Simple state machine: ────────────────────────────────────────────
enum TrafficLight { RED, YELLOW, GREEN }

public TrafficLight nextState(TrafficLight current) {
    switch (current) {
        case RED:    return TrafficLight.GREEN;
        case GREEN:  return TrafficLight.YELLOW;
        case YELLOW: return TrafficLight.RED;
        default:
            throw new IllegalStateException(
                "Unknown state: " + current);
    }
}

// ── When to use switch vs if-else: ────────────────────────────────────
//
// PREFER switch when:
//   Testing one variable against multiple EXACT values
//   All values are compile-time constants
//   3 or more cases (2 cases → if-else is cleaner)
//   Working with enum, String, or int/char
//
// PREFER if-else when:
//   Conditions involve ranges (score > 90, age >= 18)
//   Conditions test different variables
//   Using long, double, float, or boolean
//   Conditions involve method calls or complex expressions

Related Topics in Control Statements

while Loop
The while loop is a condition-controlled loop — it continues executing as long as its boolean condition remains true, without specifying in advance how many iterations will occur. It is the natural choice for reading input until end-of-stream, polling until a condition changes, retrying an operation, or any scenario where the termination condition depends on data or events that cannot be predetermined. This entry covers syntax, execution flow, common patterns, infinite loops with controlled exit, and the differences between while and for.
do-while Loop
The do-while loop is Java's only post-test loop — the condition is evaluated after the body executes, which guarantees the body runs at least once regardless of the condition's initial value. This property makes do-while the natural fit for scenarios where the first execution must happen before the first check: menu-driven programs, input validation, digest computation, and game turns. This entry covers syntax, when to use do-while over while, input validation patterns, and the subtle differences that matter in practice.
Enhanced for Loop
The enhanced for loop — also called the for-each loop — was introduced in Java 5 to provide a clean, readable syntax for iterating over arrays and any class that implements Iterable. It eliminates index management and iterator boilerplate entirely. The developer declares what each element is and what to do with it, without concerning themselves with how the iteration mechanism works. This entry covers syntax, the Iterable contract, limitations compared to the indexed loop, modification restrictions, and how for-each maps to iterators under the hood.
break Statement
The break statement immediately terminates the nearest enclosing loop or switch block and transfers control to the first statement after that block. It is one of Java's three jump statements alongside continue and return. break is essential for exiting loops early when a search condition is met, preventing infinite loops from running forever, and stopping switch execution after a matched case.