Making Use of Java 19’s Enhancements for Switch Statements and Expressions

Info

This post is part of a blog post series titled 6 New Features in Java 19 That Make Your Life Easier.

Note

This is a preview feature. In order to use it, compile the program with javac --release 19 --enable-preview Main.java and run it with java --enable-preview Main. More details about using preview features in your project can be found here.

Pattern Matching for switch was proposed as a preview feature by JEP 406 and delivered in JDK 17, and proposed for a second preview by JEP 420 and delivered in JDK 18. This JEP proposes a third preview with further refinements based upon continued experience and feedback.

For those who are not familiar with this series of JEPs, I will quickly summarize what the main goals of the “Pattern Matching for switch” JEP series are and provide some examples after. So, the main goals according to the JEP documents are:

  • Expand the expressiveness and applicability of switch expressions and statements by allowing patterns to appear in case labels
  • Allow the historical null-hostility of switch to be relaxed when desired
  • Increase the safety of switch statements by requiring that pattern switch statements cover all possible input values
  • Ensure that all existing switch expressions and statements continue to compile with no changes and execute with identical semantics

So what has changed for switch exactly? Let’s have a look.

Broadened Type Support

By extending switch statements and expressions to work on any type and allowing case labels to not only use constant values. In the following pattern switch example the selector expression o is matched with type patterns involving a class type, an enum type, a record type, and an array type, along with a null case label and a default:

record Point(int i, int j) {}
enum Color { RED, GREEN, BLUE; }

static void typeTester(Object o) {
    switch (o) {
        case null     -> System.out.println("null");
        case String s -> System.out.println("String");
        case Color c  -> System.out.println("Color: " + c.toString());
        case Point p  -> System.out.println("Record class: " + p.toString());
        case int[] ia -> System.out.println("Array of ints of length" + ia.length);
        default       -> System.out.println("Something else");
    }
}

Null Checking

We no longer need to explicitly perform a null check for the switch selector expression outside the switch statement. Checking for null is now an integral part of switch and is done by adding a separate case label:

static void testFooBar(String s) {
    switch (s) {
        case null         -> System.out.println("Oops");
        case "Foo", "Bar" -> System.out.println("Great");
        default           -> System.out.println("Ok");
    }
}

When Clause for Case Labels

Using the when clause, we can now specify our switch case label more precisely. There’s no need to add an additional if-check inside the case label:

class Shape {}
class Rectangle extends Shape {}
class Triangle  extends Shape { int calculateArea() { ... } }

static void testTriangle(Shape s) {
    switch (s) {
        case null -> 
            break;
        case Triangle t when t.calculateArea() > 100 -> 
            System.out.println("Large triangle");
        case Triangle t ->
            System.out.println("Small triangle");
        default ->
            System.out.println("Non-triangle");
    }
}

Exhaustiveness of Switch Expressions and Statements

It is required that all possible values of the selector expression are handled in the switch block. The example below is not exhaustive and will cause a compilation error:

static int coverage(Object o) {
    return switch (o) {         // Error - not exhaustive
        case String s  -> s.length();
        case Integer i -> i;
    };
}

But this example is exhausting (and thus valid):

static int coverage(Object o) {
    return switch (o) {
        case String s  -> s.length();
        case Integer i -> i;
        default -> 0;
    };
}

With the most recent additions, switch has become much more powerful and helps us to keep our code nice and clean. The examples shown above should just give an overview of how the code could look. The JEPs go much more into detail in the areas described above.

References

Leave a Comment

Your email address will not be published. Required fields are marked *