Switch Expression (JEP 361)

imagarg

Ashish Garg

Posted on February 29, 2020

Switch Expression (JEP 361)

Java has switch statement from very first release candidate. Existing implementation of Switch follows the design and syntax of procedural languages (C and C++) and supports fall through semantics by default.

A typical implementation of switch looks like below:

private static int existingSwitchWithDefault(DAY day){
    int numberOfCharacters = 0;
    switch(day){
        case MONDAY:
        case FRIDAY:
            numberOfCharacters = 6;
            break;
        case TUESDAY:
            numberOfCharacters = 7;
            break;
        case WEDNESDAY:
            numberOfCharacters = 9;
            break;
        case THURSDAY:
        case Saturday:
            numberOfCharacters = 8;
            break;
        default:
            throw new IllegalArgumentException("Invalid input "+day+" provided.");
    }
    return  numberOfCharacters;
}

Some problem with existing switch statement:

  • Default fall through

Like in other procedural languages default fall through is supported by switch statement. It’s a double edge sword, sometime useful but often dangerous and a nasty place for bug to hide.

In above example, if developer miss to put **break** and write code like this

private static int existingSwitchWithBug(DAY day){
    int numberOfCharacters = 0;
    switch(day){
        case WEDNESDAY:
            numberOfCharacters = 9; // Missed a break FALL THROUGH
        case THURSDAY:
            numberOfCharacters = 8;
            break;
    }
    return  numberOfCharacters;
}   

and method will be called like “**existingSwitchWithBug(DAY.WEDNESDAY)”** it will return 8 rather 9, because of Fall Through. Such kind of bugs not easy to find without proper unit test in place.

  • default is not

Having a default case is not mandatory in existing switch statement, if developer call above method like “**existingSwitchWithBug(DAY.MONDAY)**” it will simply return 0. This can be a valid business case but most of time this happened because developer forget to cover all required cases in switch statement.

Does it not nice if compiler make it mandatory to have a default case in switch statement?

  • Too verbose

Having break statement after every case make switch statement quite verbose to read and definitely a place to hide errors.

What is Switch Expression?

Switch expression was released as a preview feature in JDK 12 with JEP 325 (in this JEP **break** was overloaded to return a result from switch expression) based on feedback from community (developer find it confusing to use break to return from switch expression), new JEP 325 (new statement yield introduced to return and restored the original meaning of break) was introduced which implemented and released as preview feature with JDK 13.

Switch expression released as standard feature with JDK 14.

Before moving ahead its important to understand the difference between statement and expression. An expression evaluates to a value (you can print it or assign to a variable) and a statement does something, represents an action or command (if else or loops)

If you remember the switch statement example mentioned above same can be written with switch expression like below:

private static int withSwitchExpression(String day){
    int result = switch (day){
        case "Monday","Friday" -> 6;
        case "Tuesday" ->7;
        case "Wednesday" ->9;
        case "Thursday" ->8;
        default -> throw new IllegalStateException("Unexpected value: " + day);
    };
    return result;
}

Couple of things to note in above snippet:

  • A new form of switch label, “case L ->”, to signify that only the code to the right of the label is to be executed if the label is matched. Code at right of “case L ->” could only be expression, block or throw statement.
  • If a label is matched, then only the expression or statement to the right of the arrow is executed; there is no fall through.
  • Switch statement are extended so they can be used as expression, please remember the difference mentioned above between statement and expression.
  • In case of switch expression a default case is required to emphasize that all possible cases are considered, default case can be skipped if you are using Enum as case identifier, compiler can see if all cases are covered or not

Below code is perfectly fine there will not be any compile time error

switch(day){
    case MONDAY,FRIDAY,SUNDAY -> 6;
    case TUESDAY -> 7;
    case WEDNESDAY -> 9;
    case THURSDAY,SATURDAY -> 8;
};

yield

Till now we have seen example where switch expression case has only single line of code, how about if you have need to write a block something like below:

private static int switchWithBlock(String day){
    int numOfDays = switch (day){
        case "Monday","Friday" -> 6;
        case "Tuesday" ->7;
        case "Wednesday" ->9;
        case "Thursday" ->8;
        default ->{
            int len = day.length();
            yield len;
        }
    };
    return numOfDays;
}

and if you are calling above method with code like “**switchWithBlock(“bizzare”)**”, method will return 7 from default case. Here you must notice yield, it represents a statement to yield a value.

A switch statement, but not a switch expression, can be the target of a break statement. Conversely, a switch expression, but not a switch statement, can be the target of a yield statement.

### Scope of local variable

In switch statement if you declare a local variable under a case it will be accessible to other cases also (local variable visibility also works as fall through only), see below code

switch (day){
    case MONDAY:
        int expense = 50;
        System.out.println("Monday expense is " + 50);
        break;
    case TUESDAY: {
        expense = 90;
        break;
    }
}

here variable “expense” is available for TUESDAY case also even it was declared in MONDAY case.

if you want to stop this behaviour, where a variable declared in particular case block will not be available in another like in above example, you have to write code like this with switch statement

switch (day){
    case MONDAY: {
        int expense = 50;
        System.out.println("Monday expense is " + expense);
        break;
    }
    case TUESDAY: {
        int expense = 90;
        System.out.println("Tuesday expense is " +expense);
        break;
    }
}

here variable “expense” declared and use in particular case only.

Let’s see now how local variable works with switch expression, see below snippet:

switch (day){
    case MONDAY ->{
        int expense = 50;
        System.out.println("Monday expense is "+expense);
    }
    case TUESDAY ->{
        int expense = 60;
        System.out.println("Monday expense is "+expense);
    }
}   

as switch expression only allows expression, block and throw in above case is represented as block which limit the local variable scope.

Note:- Both switch statement and switch expression are valid options with JDK 14 and beyond.

💖 💪 🙅 🚩
imagarg
Ashish Garg

Posted on February 29, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related