29

As part of Java SE 12, switch expressions were introduced and since Java SE 14, they have been standardized. How are they different from switch statements?

Naman
  • 27,789
  • 26
  • 218
  • 353
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • 4
    What does standardized mean vs. introduced? – rogerdpack Jan 26 '21 at 17:00
  • 6
    @rogerdpack This must refer to switch expressions being introduced as Preview feature in JDK 12 - fully usable and complete, enabled through the compiler options, still amenable to (breaking) change in future versions based on user feedback. In JDK 14 this was consolidated as a standard feature that won't change anymore in future versions. – tryman Jan 27 '21 at 09:48

4 Answers4

40

The switch statement:

Unlike the if/else if/else statement, a switch statement can have a number of possible execution paths. A switch works with the primitive types, byte, short, char, and int, their respective wrapper types (Byte, Short, Character, and Integer), enumerated types, and the String type1. While an if-else statement is used to test expressions based on ranges of values or conditions, a switch statement is used to test expressions based only on a single value.

Demo

enum PaymentStatus {
    UNPAID, PARTPAID, PAID, DISPUTED, UNKNOWN;
}

public class Main {
    public static void main(String[] args) {
        String message = "";
        PaymentStatus paymentStatus = PaymentStatus.PARTPAID;

        switch (paymentStatus) {
        case UNPAID:
            message = "The order has not been paid yet. Please make the minimum/full amount to procced.";
            break;
        case PARTPAID:
            message = "The order is partially paid. Some features will not be available. Please check the brochure for details.";
            break;
        case PAID:
            message = "The order is fully paid. Please choose the desired items from the menu.";
            break;
        default:
            throw new IllegalStateException("Invalid payment status: " + paymentStatus);
        }
        System.out.println(message);
    }
}

Output:

The order is partially paid. Some features will not be available. Please check the brochure for details.

The switch expression:

The switch expression was introduced with Java SE 12. However, it remained as a Preview feature in Java SE 12 and 13 and finally got standardized with Java SE 14. Like any expression, switch expressions evaluate to a single value, and can be used in statements. It also introduced "arrow case" labels eliminating the need for break statements to prevent fall through. As of Java SE 15, there is no change in the supported data types (mentioned in the switch statement section above).

Demo

enum PaymentStatus {
    UNPAID, PARTPAID, PAID, DISPUTED, UNKNOWN;
}

public class Main {
    public static void main(String[] args) {
        PaymentStatus paymentStatus = PaymentStatus.PARTPAID;

        String message = switch (paymentStatus) {
        case UNPAID -> "The order has not been paid yet. Please make the minimum/full amount to procced.";
        case PARTPAID -> "The order is partially paid. Some features will not be available. Please check the brochure for details.";
        case PAID -> "The order is fully paid. Please choose the desired items from the menu.";
        default -> throw new IllegalStateException("Invalid payment status: " + paymentStatus);
        };

        System.out.println(message);
    }
}

Output:

The order is partially paid. Some features will not be available. Please check the brochure for details.

The switch expression with yield:

Since Java SE 13, you can use yield statement, instead of the arrow operator (->), to return a value from a switch expression.

Demo

enum PaymentStatus {
    UNPAID, PARTPAID, PAID, DISPUTED, UNKNOWN;
}

public class Main {
    public static void main(String[] args) {
        PaymentStatus paymentStatus = PaymentStatus.PARTPAID;

        String message = switch (paymentStatus) {
        case UNPAID:
            yield "The order has not been paid yet. Please make the minimum/full amount to procced.";
        case PARTPAID:
            yield "The order is partially paid. Some features will not be available. Please check the brochure for details.";
        case PAID:
            yield "The order is fully paid. Please choose the desired items from the menu.";
        default:
            throw new IllegalStateException("Invalid payment status: " + paymentStatus);
        };

        System.out.println(message);
    }
}

Output:

The order is partially paid. Some features will not be available. Please check the brochure for details.

1 The support for String was added with JDK 7

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • "Unlike the if/else if/else statement, a switch statement can have a number of possible execution paths" sounds like `switch` could execute multiple cases for one switch. If you mean that `switch` supports fallthrough it would be much more clear to mention that explicitly. Other than that if/else if/else is just different syntax compared to switch statement because you can easily convert any switch statement without fallthrough to if/else if/else format. – Mikko Rantalainen Jun 22 '21 at 09:38
13

Nice writeup! But I might also add the ability to have multiple cases for a single case statement. The following example is very contrived (there are many better ways to achieve it). It does a simple frequency count of the vowels, digits, consonants, and other characters in a string.

int count[] = new int[4];

String s = "829s2bi9jskj*&@)(so2i2ksso";

for (char c : s.toCharArray()) {
      int i = switch (c) {
                case  'a', 'e', 'i', 'o', 'u' -> 0;
                case  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> 1;
                case  'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l',
                      'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w',
                      'x', 'y', 'z' -> 2;
                default -> 3;
      };
      count[i]++;
}
System.out.printf("vowels  - %d%n", count[0]);
System.out.printf("digits  - %d%n", count[1]);
System.out.printf("consonants - %d%n", count[2]);
System.out.printf("other   - %d%n", count[3]);

Prints

vowels  - 4
digits  - 7
consonants - 10
other   - 5
WJS
  • 36,363
  • 4
  • 24
  • 39
6

Adding to existing answers: yield can also be used with -> and its main purpose is to allow the use of a block when a single expression is not sufficient for a given case:

var test = switch (value) {
    case A -> 1;
    case B -> 2;
    case C -> {
        System.err.println("neither A nor B"); // or some calculation
        yield -1;
    }
}

I would also mention JEP-354 where the switch expression is proposed and described.
Formal specification can be found, as always in the Java Language Specification.

3

Adding to the above answers one can look at the current “shortfalls” with switch statement which switch expression solve:

Switch Statement:

  • Issue 1: Accidental Fall-through
  • Issue 2: Variable scoping
  • Issue 3: No return value

Switch expression:

  • No fallthrough
  • Combined constants
  • Blocked scope
  • Return yield

EXAMPLE:

Switch Statement:

private static void oldSwitchStatement(String month) {

    int i = 0;
    String quarter = "";

    switch (month) {
        case "JAN":
        case "FEB":
        case "MAR":
            i = i + 1;
            quarter = "Q1";
            // break;
        case "APR":
        case "MAY":
        case "JUN":
            i = i + 2;
            quarter = "Q2";
            // break;
        case "JUL":
        case "AUG":
        case "SEP":
            i = i + 3;
            quarter = "Q3";
            // break;
        case "OCT":
        case "NOV":
        case "DEC":
            i = i + 4;
            quarter = "Q4";
        default:
            System.out.println("Unknown case");
    }

    System.out.println("QUARTER: "+ i + " "+ quarter);
}

Switch Expression

private static String newSwitchExpressionYield(String month) {

    return switch (month) {
        case "JAN", "FEB", "MAR" -> "Q1";
        case "APR", "MAY", "JUN" -> {
            System.out.println("Using yield.");
            yield "Q2";
        }
        case "JUL", "AUG", "SEP" -> "Q3";
        case "OCT", "NOV", "DEC" -> "Q4";
        default -> "Unknown case";
    };
}

To test the above pass oldSwitchStatement("APR"); and newSwitchExpressionYield("APR"); and see the resutls.

Ithar
  • 4,865
  • 4
  • 39
  • 40