Mastering Java Switch Statement [In-Depth Tutorial]


JAVA

Author: Bashir Alam
Reviewer: Deepak Prasad

Getting started with Java switch statement

When developing software in Java, one of the most fundamental concepts you'll encounter is control flow. Control flow dictates the order in which your code is executed, enabling you to implement complex logic and decision-making algorithms. Among various control flow constructs like if-else, while, and for, the switch statement holds a unique place. This article aims to be your comprehensive guide to understanding the Java Switch Statement, diving deep into its syntax, usage, and best practices.

 

Control Flow in Java

Control flow in programming refers to the order in which the computer executes statements in a script. Java, like most high-level programming languages, comes with several structures for controlling the flow of execution in programs. These are essential for implementing algorithms and carrying out operations based on conditions. Understanding control flow is critical for writing effective and efficient Java programs.

Java provides various types of control flow statements:

  • Conditional Statements: These include if, if-else, and switch statements. They are used to perform different actions based on different conditions.
  • Looping Statements: These include for, while, and do-while loops. Loops are used for repetitive tasks where the number of iterations is known beforehand (for loop) or determined dynamically (while and do-while loops).
  • Jump Statements: These are break, continue, and return statements. They are used to alter the flow of loops and methods.

 

Importance of the Switch Statement in Java

The switch statement in Java serves as a cleaner, more readable alternative to a series of nested if-else statements for multiple condition checks. It improves code readability and performance when you need to evaluate a variable against multiple constant values. If you are dealing with scenarios where a single variable can have multiple constant values and you want to execute different blocks of code, switch is often the better choice.

 

Syntax and Structure

The switch statement in Java follows a specific syntax that you must adhere to when using it in your code. Below is the general structure:

switch (expression) {
    case value1:
        // Code block 1
        break;
    case value2:
        // Code block 2
        break;
    // ... additional cases
    default:
        // Default code block
        break;
}

In this structure:

  • expression: This is the variable or expression that will be evaluated. The result of the expression should be compatible with the types allowed in a switch statement (byte, short, char, int, String, or an enum).
  • case value1, value2, ...: These are the constant values against which the expression is compared. If the expression matches any case, the code block following that case is executed.
  • break: The break statement is used to exit the switch statement after a case is executed. If omitted, the code will fall through to the subsequent case blocks.
  • default: This block is executed if none of the case blocks match the expression. It is optional but recommended for covering cases that are not explicitly handled.

 

Basic Usage

To get a clear understanding of how a switch statement works, let's start with a straightforward example. Suppose you want to write a program that takes a number from 1 to 7 and prints out the corresponding day of the week. Here's how you can use a switch statement to achieve this:

public class Main {
    public static void main(String[] args) {
        int day = 3;  // Change this value to test different days

        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;
            case 6:
                System.out.println("Saturday");
                break;
            case 7:
                System.out.println("Sunday");
                break;
            default:
                System.out.println("Invalid day");
                break;
        }
    }
}

In this example, the variable day holds the value 3, representing Wednesday. The switch statement compares day against each case. When it finds a match (case 3), it executes the corresponding code block (System.out.println("Wednesday");) and then breaks out of the switch statement because of the break keyword.

 

Switch with Primitive Types

In Java, you can use the switch statement with several primitive data types like int, char, and byte. However, it's important to note that switch does not work with float and double data types. In this section, we will focus on how to use switch with int and char types, illustrated with examples.

 

Switch with Integers

Using integers in a switch statement is straightforward. The switch evaluates the expression inside its parentheses and executes the case block that matches the evaluated value.

public class SwitchExample {
    public static void main(String[] args) {
        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;
            default:
                System.out.println("Invalid day");
        }
    }
}

In this example, the switch evaluates the day variable. It finds that the day is 3, so it executes the block under case 3, outputting "Wednesday".

 

Switch with Characters

You can also use char values in a switch statement. Similar to integers, the switch matches the case based on the char value and executes the corresponding block.

public class CharSwitchExample {
    public static void main(String[] args) {
        char grade = 'A';
        
        switch(grade) {
            case 'A':
                System.out.println("Excellent");
                break;
            case 'B':
                System.out.println("Good");
                break;
            case 'C':
                System.out.println("Average");
                break;
            default:
                System.out.println("Invalid grade");
        }
    }
}

In this example, the switch evaluates the grade variable. Since the grade is 'A', it matches with case 'A' and outputs "Excellent".

 

Switch with Enums

Java enum types are also compatible with switch statements. Using enum with switch can be very useful for improving code readability and maintainability. Enumerations provide a way to define a set of named constants, making your code more self-explanatory and easier to read.

To demonstrate, let's consider an example where we have an enum defining the days of the week.

public enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

You can use this enum in a switch statement as follows:

public class EnumSwitchExample {
    public static void main(String[] args) {
        Day today = Day.WEDNESDAY;

        switch (today) {
            case MONDAY:
                System.out.println("Start of the work week");
                break;
            case TUESDAY:
                System.out.println("Second day");
                break;
            case WEDNESDAY:
                System.out.println("Hump day");
                break;
            case THURSDAY:
                System.out.println("Almost there");
                break;
            case FRIDAY:
                System.out.println("Last work day");
                break;
            case SATURDAY:
            case SUNDAY:
                System.out.println("Weekend!");
                break;
            default:
                System.out.println("Invalid day");
        }
    }
}

In this example, the switch statement evaluates the today variable, which is of type Day. Since today is set to Day.WEDNESDAY, it matches the case case WEDNESDAY: and outputs "Hump day".

 

Switch with Strings

Starting from Java 7, the switch statement can be used with String objects, making it even more versatile for text-based conditions. Before this feature was introduced, developers often had to resort to long chains of if-else if-else statements to perform operations based on string values.

To illustrate how a switch statement can be used with strings, consider the following example:

public class StringSwitchExample {
    public static void main(String[] args) {
        String day = "Wednesday";

        switch (day) {
            case "Monday":
                System.out.println("Start of the work week");
                break;
            case "Tuesday":
                System.out.println("Second day");
                break;
            case "Wednesday":
                System.out.println("Hump day");
                break;
            case "Thursday":
                System.out.println("Almost there");
                break;
            case "Friday":
                System.out.println("Last work day");
                break;
            case "Saturday":
            case "Sunday":
                System.out.println("Weekend!");
                break;
            default:
                System.out.println("Invalid day");
        }
    }
}

In this example, the switch statement evaluates the string variable day. The case labels are string literals, allowing for a clear and direct comparison.

Points to Consider

  • Case Sensitivity: Remember that the string comparison in the switch statement is case-sensitive. "Monday" and "monday" would be considered different values.
  • Null Handling: Be cautious while using strings, as a NullPointerException will be thrown if the expression in the switch is null.
  • String Equality: The switch statement uses the equals() method for string comparison, not ==. Therefore, string cases should be constant expressions to ensure the equality check functions as expected.

 

Nested Switch Statements

Nested switch statements refer to a switch statement that resides inside another switch statement. It can be useful in scenarios where you have multiple levels of condition to check.

Here is a simple example to demonstrate how nested switch statements work:

public class NestedSwitchExample {
    public static void main(String[] args) {
        char grade = 'A';
        int level = 2;

        switch (grade) {
            case 'A':
                System.out.println("Excellent grade!");
                switch (level) {
                    case 1:
                        System.out.println("You scored above 90");
                        break;
                    case 2:
                        System.out.println("You scored between 85-90");
                        break;
                    default:
                        System.out.println("Invalid level for grade A");
                }
                break;
            case 'B':
                System.out.println("Good grade!");
                // Nested switch could go here
                break;
            case 'C':
                System.out.println("Fair grade!");
                // Nested switch could go here
                break;
            default:
                System.out.println("Invalid grade");
        }
    }
}

In this example, the outer switch statement evaluates the variable grade. Inside the case for 'A', there is another switch statement that evaluates the variable level.

 

The Default Case

In a switch statement, the default case serves as a fallback option when none of the other cases match the switch expression. This is especially useful for handling unexpected or invalid values in a controlled manner, providing a way to execute a block of code when nothing else matches.

The default case in a switch statement does not require a break statement, although it's a good practice to include one for readability and future modifications. Here's how you can include a default case:

switch(expression) {
    case value1:
        // code block
        break;
    case value2:
        // code block
        break;
    default:
        // code block
        break;
}

Here is an example that demonstrates the use of the default case:

public class DefaultCaseExample {
    public static void main(String[] args) {
        int day = 8;  // An invalid day value

        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;
            case 6:
                System.out.println("Saturday");
                break;
            case 7:
                System.out.println("Sunday");
                break;
            default:
                System.out.println("Invalid day");
        }
    }
}

In this example, the variable day contains an invalid value (8). Since there are no cases that match this value, the default case is executed, and "Invalid day" is printed to the console.

 

Break and Fall-Through Behavior

Understanding Fall-Through in Java Switch Statements

In a Java switch statement, "fall-through" refers to the behavior where, once a matching case is found, all subsequent case blocks are executed in sequence until either a break statement is encountered or the switch statement ends. This can lead to unintended results if not handled properly.

Fall-through is actually a feature of C and C++ that has been inherited by Java. It allows for more flexible and compact code in some situations, but it can be a source of confusion and bugs if not used cautiously.

Here's an example to illustrate fall-through:

int day = 3;
switch(day) {
    case 1:
        System.out.println("Sunday");
    case 2:
        System.out.println("Monday");
    case 3:
        System.out.println("Tuesday");
    // ...and so on
}

If day is set to 3, this code will print:

Tuesday

This might not be the intended outcome because there's no break statement in the preceding case blocks.

 

The Role of the break Statement

The break statement is used to terminate the current case and exit the switch block. If you do not use a break, Java will execute all subsequent case blocks until it finds a break, leading to possibly incorrect or unexpected behavior.

Here's the general structure demonstrating the use of break:

switch(expression) {
    case value1:
        // code block
        break;
    case value2:
        // code block
        break;
    default:
        // code block
        break;
}

 

Why Is It Important to Use break?

Omitting the break statement can sometimes be useful, but it can also be a source of bugs if not handled carefully. Using break ensures that only the code block corresponding to the first matching case gets executed.

With break Statement

int number = 2;

switch(number) {
    case 1:
        System.out.println("One");
        break;
    case 2:
        System.out.println("Two");
        break;
    default:
        System.out.println("Other");
}

This will output:

Two

Without break Statement

int number = 2;

switch(number) {
    case 1:
        System.out.println("One");
    case 2:
        System.out.println("Two");
    default:
        System.out.println("Other");
}

This will output:

Two
Other

As you can see, not using break leads to a fall-through, and both the case 2 and default code blocks are executed. This may or may not be the behavior you intend.

 

Switch Expressions (Java 12+)

Java 12 introduced a new feature called "Switch Expressions" which greatly simplifies the syntax of switch statements and makes the code more readable. Unlike traditional switch statements, switch expressions are more concise, safer, and allow you to return a value. They also eliminate the need for break statements to prevent fall-through, reducing the chance of bugs.

In switch expressions, you can use the yield keyword to return a value from a case. The arrow -> can also be used to simplify the syntax. Here's the general structure of a switch expression:

var result = switch(expression) {
    case value1 -> {
        // code block
        yield returnValue1;
    }
    case value2 -> returnValue2;
    default -> returnValueDefault;
};

Let's consider an example where you need to find out the number of days in a given month:

String month = "Feb";
int days = switch (month) {
    case "Jan", "Mar", "May", "Jul", "Aug", "Oct", "Dec" -> 31;
    case "Apr", "Jun", "Sep", "Nov" -> 30;
    case "Feb" -> 28;
    default -> throw new IllegalArgumentException("Invalid month: " + month);
};

System.out.println("Days in " + month + ": " + days);

In this example, each case block directly returns a value, making the code more compact and straightforward. The switch expression assigns the number of days to the days variable based on the month provided, and if an invalid month is given, it will throw an IllegalArgumentException.

 

Using Switch Expressions with Lambdas (Java 12+)

With the advent of Java 12 and later versions, switch statements were enhanced to become switch expressions. This change allows for more functional programming styles, such as the use of lambdas in some contexts.

Example 1: Using Arrow Syntax for Simpler Cases

Java 12 introduced a more streamlined syntax using the arrow (->) to eliminate the need for break.

int number = 3;
String numberString = switch (number) {
    case 1 -> "one";
    case 2 -> "two";
    case 3 -> "three";
    default -> "unknown";
};
System.out.println("You selected: " + numberString);

Example 2: Combining Multiple Cases into One

Using the arrow syntax, you can also combine multiple cases into a single case, separating them by commas.

char grade = 'B';
String result = switch (grade) {
    case 'A', 'B' -> "Excellent";
    case 'C' -> "Good";
    case 'D' -> "Need Improvement";
    default -> "Invalid grade";
};
System.out.println("Result: " + result);

Example 3: Using Block for Complex Logic

When you have complex logic for a case, you can use blocks.

int day = 5;
String dayType = switch (day) {
    case 1, 7 -> "Weekend";
    case 2, 3, 4, 5, 6 -> {
        if (day == 5) {
            yield "Almost Weekend";  // Using yield to return the value
        } else {
            yield "Working Day";
        }
    }
    default -> "Invalid day";
};
System.out.println("Day type: " + dayType);

Example 4: Switch Expressions in Lambdas

While direct use of switch expressions inside lambda expressions may not be possible, you can wrap them in a method and then use method references.

Function<Integer, String> getDayType = day -> {
    return switch (day) {
        case 1, 7 -> "Weekend";
        case 2, 3, 4, 5, 6 -> "Working Day";
        default -> "Invalid day";
    };
};

System.out.println("Day type is: " + getDayType.apply(5));

 

When to Use Switch Statements for Optimal Performance

The performance of switch statements in Java is often better than a series of if-else if-else statements when you have multiple cases to consider, especially for primitive types and Enums. The JVM optimizes switch statements using a technique called tableswitch or lookupswitch, depending on the sparseness or density of the case values. This results in faster and more efficient bytecode execution.

 

Example 1: Performance Comparison with If-Else

Let's compare the performance of a switch statement with an if-else block.

Switch Version

long startTime = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
    switch (i % 3) {
        case 0:
            // some logic here
            break;
        case 1:
            // some logic here
            break;
        case 2:
            // some logic here
            break;
    }
}
long endTime = System.nanoTime();
System.out.println("Switch Time: " + (endTime - startTime) + " ns");

If-Else Version

startTime = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
    int n = i % 3;
    if (n == 0) {
        // some logic here
    } else if (n == 1) {
        // some logic here
    } else if (n == 2) {
        // some logic here
    }
}
endTime = System.nanoTime();
System.out.println("If-Else Time: " + (endTime - startTime) + " ns");

When you run these two blocks of code, you will generally find that the switch version is faster, especially as the number of cases increases.

 

Example 2: Performance with Enums

Enums in switch statements are highly optimized by the Java compiler, making them efficient for state machines or complex logic trees.

enum State {START, RUNNING, PAUSED, STOPPED}

long startTime = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
    State s = State.values()[i % 4];
    switch (s) {
        case START:
        case RUNNING:
        case PAUSED:
        case STOPPED:
            // some logic here
            break;
    }
}
long endTime = System.nanoTime();
System.out.println("Enum Switch Time: " + (endTime - startTime) + " ns");

Using Enums in switch statements is both readable and performance-optimized, making it a recommended practice for many use-cases.

 

Common Mistakes and How to Avoid Them

1. Forgetting the break Statement

One of the most common mistakes when using the switch statement in Java is forgetting to use the break keyword, leading to fall-through behavior.

switch (season) {
    case "Spring":
        System.out.println("Flowers bloom");
    case "Summer":
        System.out.println("It's hot!");
    case "Autumn":
        System.out.println("Leaves fall");
    case "Winter":
        System.out.println("It snows");
}

If season is "Spring," all the following case blocks will also be executed, printing all four sentences. Always include a break statement in each case block unless you explicitly want fall-through behavior.

 

2. Using Variables for Case Labels

Java does not support variables or non-constant expressions as case labels.

int x = 2;
switch (x) {
    case x:  // Compilation Error
        System.out.println("It's 2");
        break;
}

Only use literals, enum constants, or final variables as case labels.

 

3. Ignoring the default Case

Ignoring the default case means that you can miss handling some cases.

int grade = 20;
switch (grade) {
    case 10:
        System.out.println("Excellent");
        break;
    case 5:
        System.out.println("Average");
        break;
}

In this example, if grade is 20, nothing will be printed. Always include a default case to handle all unanticipated cases.

 

4. Using Switch for Floating-Point Numbers

Java doesn't allow floating-point numbers in switch-case statements, but beginners sometimes attempt to do so.

float num = 1.1f;
switch (num) { // Compilation Error
    case 1.1: 
        // Code
        break;
}

Use if-else statements for conditions involving floating-point numbers.

 

Frequently Asked Questions about Java's Switch Statement

1. Can I use floating-point numbers in a Java switch statement?

No, you cannot use floating-point numbers like float or double in a switch statement. It supports only integer types, enumerated types, String, and some special classes like Character, Byte, Short, and Integer.

 

2. Do I always have to include a default case in a switch statement?

No, it's not mandatory to include a default case, but it's a good practice. The default case acts as a fallback if none of the case conditions are met.

 

3. Can I use string literals in a Java switch statement?

Yes, starting from Java 7, you can use String literals in a switch statement.

 

4. What happens if I forget to use the break statement?

Omitting the break statement leads to "fall-through" behavior, where all the succeeding case blocks will be executed until a break is encountered or the switch block ends.

 

5. Can I use null in a switch statement with Strings?

No, using null in a switch statement for Strings will result in a NullPointerException.

 

6. Can I declare a variable inside a switch statement?

Yes, you can declare variables inside a switch statement, but the scope of that variable will be limited to the block in which it is declared.

 

7. Can I use duplicate case values?

No, duplicate case values are not allowed and will result in a compile-time error.

 

8. Can I use a switch statement with boolean values?

No, switch statements don't support boolean types.

 

9. What are switch expressions in Java 12+?

Java 12 introduced "switch expressions" that allow you to return a value directly from a switch statement, making your code more readable and less error-prone. They are also more concise and can simplify the use of break and default.

 

10. Is the order of case statements important?

The order of case statements doesn't affect the logic as only the matching case block will be executed. However, it's common to put the default case at the end for readability.

 

Summary

The switch statement is a powerful feature in Java, offering a more readable and efficient alternative to a series of if-else statements for handling multiple conditions. In this article, we've covered various aspects of using switch statements effectively, from their basic syntax to more advanced use-cases and performance considerations.

Here are the key takeaways:

  • Syntax & Structure: The basic syntax involves using the switch keyword, followed by a variable or expression that is checked against multiple case values.
  • Supported Types: switch can be used with primitive integer types (byte, short, char, int), Enums, and String. It doesn't support float, double, or boolean types.
  • Default Case: Including a default case is a good practice as it serves as a fallback option when none of the case values match.
  • Break Statement: The break keyword is essential for preventing "fall-through," where multiple case blocks could be executed in sequence if not explicitly broken out of.
  • Advanced Features: Java 12+ introduced switch expressions, which allow you to both simplify syntax and eliminate some common sources of errors.
  • Performance: switch statements are generally more efficient than if-else chains for multiple conditions and should be preferred when applicable.
  • Best Practices: Always cover all possible case scenarios or include a default case, avoid duplicate case values, and use break to prevent fall-through.
  • Common Pitfalls: Watch out for duplicate case values and remember that case values must be compile-time constants. Also, be cautious of fall-through if you omit a break statement.

 

Further Reading

java switch 
More about java switch statements

 

Views: 113
Bashir Alam

Bashir Alam

He is a Computer Science graduate from the University of Central Asia, currently employed as a full-time Machine Learning Engineer at uExel. His expertise lies in Python, Java, Machine Learning, OCR, text extraction, data preprocessing, and predictive models. You can connect with him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment