You are currently viewing Java Switch Statement
java_logo

Java Switch Statement

Navigating through multiple branches of code based on a single value can be both complex and verbose in Java. Enter the switch statement – a versatile and efficient alternative to the traditional if statement. This construct excels in scenarios where numerous possible branches need to be considered for a given value. In this exploration, we’ll delve into the intricacies of the switch statement, demystify its structure, highlight its elegance, and emphasize its role in crafting code that is not only readable but also easier to maintain.

1. Basic Structure

switch (expression) {
    case value1:
        // Code to be executed if expression equals value1
        break;
    case value2:
        // Code to be executed if expression equals value2
        break;
    // Additional cases as needed
    default:
        // Code to be executed if none of the cases match
}
  • switch: Keyword marking the beginning of the switch statement.
  • (expression): The value or expression being evaluated against different cases. The parentheses are required
  • {}: Enclosed block containing the different case statements and the optional default statement.
  • case value:: Specific values to match against the expression.
  • break;: Optional keyword to exit the switch statement after a case is executed.
  • default:: Optional case that is executed if none of the preceding cases match.

2. Data Types

In Java’s switch statement, the target variable being evaluated at runtime plays a crucial role in determining the flow of execution. This target variable can be of various data types, each with its own characteristics and nuances:

  • int and Integer
  • byte and Byte
  • short and Short
  • char and Character
  • String
  • enum values
  • var (if the type resolves to one of the preceding types)

This means that booelan, long, float and double are not supported by switch statements

3. Control Flow

public class DaysOfWeekExample {
    public static void main(String[] args) {
        int dayOfWeek = 3; // Assuming 3 represents Wednesday

        switch (dayOfWeek) {
            case 1:
                System.out.println("It's Monday!");
                break;
            case 2:
                System.out.println("Happy Tuesday!");
                break;
            case 3:
                System.out.println("Hello Wednesday!");
                break;
            case 4:
                System.out.println("Almost there! Thursday's here.");
                break;
            case 5:
                System.out.println("Fantastic Friday! Weekend is near.");
                break;
            default:
                System.out.println("Enjoy your weekend!");
        }
    }
}

In this example, the switch statement evaluates the dayOfWeek variable and prints a message based on the corresponding case. The default case handles any unexpected values. Since the dayOfWeek is 3, the output will be:

Hello Wednesday!

Now lets see what happens if we dont use the break; keyword:

public class DaysOfWeekWithoutBreaks {
    public static void main(String[] args) {
        int dayOfWeek = 3; // Assuming 3 represents Wednesday

        switch (dayOfWeek) {
            case 1:
                System.out.println("It's Monday!");
            case 2:
                System.out.println("Happy Tuesday!");
            case 3:
                System.out.println("Hello Wednesday!");
            case 4:
                System.out.println("Almost there! Thursday's here.");
            case 5:
                System.out.println("Fantastic Friday! Weekend is near.");
            default:
                System.out.println("Enjoy your weekend!");
        }
    }
}

In this case, notice the absence of break statements. When a matching case is found, the code continues to execute all subsequent cases until the end or until a break statement is encountered. This behavior is known as “fall-through.” When dayOfWeek is 3 (Wednesday), the output will be:

Hello Wednesday!
Almost there! Thursday's here.
Fantastic Friday! Weekend is near.
Enjoy your weekend!

4. Case Values

The values specified in each case statement within a switch block must be compile-time constant values. This means that the values must be determinable by the compiler at compile time, allowing it to make decisions about code structure and optimizations. Let’s break down what is considered acceptable:

  1. Literals: Literal values, such as numeric literals (1, 2), character literals ('A', 'B'), or string literals ("Monday", "Tuesday"), are permissible case values.
  2. Enum Constants: Enum constants represent a set of named values of the same data type and are compile-time constants.
  3. Final Constant Variables: Final variables (constants) of the same data type as the switch expression are allowed as case values.
        private int getRuntimeValue() {
            return 2;
        }
        
        final int constantValue = 42;
        int switchValue = 2;
        int runtimeEvaluatedValue = getRuntimeValue();

        switch (switchValue) {
            case 1:  // Literal
                System.out.println("Case 1");
                break;
            case constantValue:  // Literal
                System.out.println("Case constantValue");
                break;
            case switchValue:  // compilation error
                System.out.println("Case 2");
                break;
            case runtimeEvaluatedValue:  // compilation error 
                System.out.println("Case with runtime-evaluated value");
                break;
            default:
                System.out.println("Default case");
        }
  1. The literal values 1 and constantValue (which is a final constant) are compile-time constants. They can be determined by the compiler during the compilation process, making them acceptable as case values.
  2. The case case switchValue attempts to use a variable (switchValue) as a case value. This is not allowed in a switch statement because the variable is not marked final.
  3. The case case runtimeEvaluatedValue attempts to use a value that is determined at runtime (getRuntimeValue()). This is not allowed in a switch statement because case values must be constants. The value of runtimeEvaluatedValue is not known until the program runs, leading to a compilation error.

In summary, the key takeaway is that switch case values must be constants that can be determined by the compiler at compile time to ensure efficient code generation and optimization.

5. Numeric Promotion and Casting

Numeric promotion and casting play significant roles in ensuring the proper evaluation of expressions within a switch statement in Java. Let’s explore these concepts with a code example.

  • Numeric promotion is an implicit type conversion that occurs when smaller numeric types are involved in expressions with larger numeric types. The promotion ensures that the operands have a common data type before the operation is performed.
  • Casting is the explicit conversion of a value from one data type to another. It’s crucial when dealing with narrowing conversions (converting a larger type to a smaller type) or when the compiler needs guidance on how to treat a value.
public class NumericPromotionAndCastingInSwitch {
    public static void main(String[] args) {
        char charValue = 'C';

        switch (charValue) {
            case 'A':
                System.out.println("Case A");
                break;
            case 10000000: // compiler error
                System.out.println("Case 10000000");
                break;
            case 67:
                System.out.println("Case C (Numeric Promotion)");
                break;
            case (byte) 2:
                System.out.println("Case 2 (Casting from int to byte)");
                break;
            default:
                System.out.println("Default case");
        }
    }
}
  1. Case 10000000: This case attempts to use an int literal (10000000) as a case value. The value is too large for a char, and the compiler throws an error. Error Message: “incompatible types: possible lossy conversion from int to char”
  2. Case 67 (Numeric Promotion): The charValue is of type char, and the case value 67 is an int literal. Numeric promotion occurs, converting the char to its Unicode value (67) and then promoting it to an int. The output will be: “Case C (Numeric Promotion)”
  3. Case (byte) 2 (Casting from int to byte): The case value (byte) 2 involves explicit casting from int to byte. The byteValue is of type byte, and the case value (byte) 2 is a constant expression of type byte. The output will be: “Case 2 (Casting from int to byte)”