Skip to content

Java Switch Expressions (JEP 361): Arrows, yield, No break

Brass model railway track on terracotta, seen from above: one track splits at a set of points into three, and a glowing white sphere rolls onto the middle one

Switch expressions were released in Java 14 under Project Amber.

Switch expressions are two enhancements that can be used independently but also combined:

  1. Arrow notation without break and fall-throughs
  2. Using switch as an expression with a return value

Let’s look at the changes one by one (I’m using the examples from JEP 361, slightly modified).

Starting Point

In the following example, we print the word length for a given day of the week. For the last two cases, I wrote the code a bit more complicated than necessary to demonstrate what is possible with switch expressions.

switch (day) {
  case MONDAY:
  case FRIDAY:
  case SUNDAY:
    System.out.println(6);
    break;
  case TUESDAY:
    System.out.println(7);
    break;
  case THURSDAY:
  case SATURDAY:
    System.out.println((int) Math.pow(2, 3));
    break;
  case WEDNESDAY:
    int three = 1 + 2;
    System.out.println(three * three);
    break;
}

This notation is confusing and error-prone due to the so-called “fall-throughs”, i.e., the continuation of execution on the following case if the previous one was not terminated with a break statement.

Accordingly, such constructs are marked as code smells by static code analysis (SCA) tools such as Sonar, Checkstyle, and PMD:

Static code analysis (SCA) warnings for “switch” statements without “break”
Static code analysis (SCA) warnings for “switch” statements without “break”

Switch with Arrow Notation

The following example shows using an arrow instead of a colon, starting with Java 14. The following rules apply:

  • Before the arrow, you may list several cases separated by commas.
  • The arrow may be followed by either a single code statement (lines 2, 3, and 4) or a code block in curly braces (lines 5 to 8).
  • break statements are omitted in this notation.
  • Arrow and colon form cannot be mixed within one switch; otherwise, the compiler reports “different case kinds used in the switch”.

Here is a sample code for a switch statement in arrow notation:

switch (day) {
  case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
  case TUESDAY                -> System.out.println(7);
  case THURSDAY, SATURDAY     -> System.out.println((int) Math.pow(2, 3));
  case WEDNESDAY -> {
    int three = 1 + 2;
    System.out.println(three * three);
  }
}

Modern IDEs like IntelliJ recognize the improvement potential and offer an automatic conversion to the new format:

Automatic replacement of “switch” statements
Automatic replacement of “switch” statements

Switch as an Expression with a Return Value

We often use switch to assign a case-specific value to a variable. In the following example, instead of printing the weekday’s length, we store it in the numLetters variable.

The last two cases are again intentionally written verbosely to show what is possible with switch expressions.

int numLetters;
switch (day) {
  case MONDAY:
  case FRIDAY:
  case SUNDAY:
    numLetters = 6;
    break;
  case TUESDAY:
    numLetters = 7;
    break;
  case THURSDAY:
  case SATURDAY:
    numLetters = (int) Math.pow(2, 3);
    break;
  case WEDNESDAY:
    int three = 1 + 2;
    numLetters = three * three;
    break;
  default:
    throw new IllegalStateException("Unknown day: " + day);
}

To use the variable afterward, this conventional notation – even though we’ve covered every weekday – requires us to either initialize the variable beforehand or specify a default case. Otherwise, the compiler would abort with the error message “variable numLetters might not have been initialized”.

As of Java 14, we can convert this statement into an expression. To do so, we return each value using the new keyword yield. We then assign the result of the switch expression directly to the variable:

int numLetters = switch (day) {
  case MONDAY, FRIDAY, SUNDAY:
    yield 6;

  case TUESDAY:
    yield 7;

  case THURSDAY, SATURDAY:
    yield (int) Math.pow(2, 3);

  case WEDNESDAY:
    int three = 1 + 2;
    yield three * three;

  default:
    throw new IllegalStateException("Unknown day: " + day);
};

The comma-separated labels from the previous section also work in the colon form.

yield is a so-called “contextual keyword”; it therefore only has meaning in the context of a switch expression. Should you have used yield as a variable name in your source code – don’t worry; you can still do that. Even something like this would be allowed:

int yield = 5; yield yield + yield;

By the way, the default case is unnecessary here (in contrast to the conventional notation) – more about this in the section Exhaustiveness Analysis for Enums.

Arrow Notation and Switch Expression Combined

The switch expression just shown becomes much more elegant if we write it in arrow notation. We can write the return value

  • directly behind the arrow (lines 2 and 3),
  • as an expression or method call behind the arrow (line 4),
  • or return it with yield from a code block (line 7).
int numLetters = switch (day) {
  case MONDAY, FRIDAY, SUNDAY -> 6;                     // line 2
  case TUESDAY                -> 7;                     // line 3
  case THURSDAY, SATURDAY     -> (int) Math.pow(2, 3);  // line 4
  case WEDNESDAY              -> {
    int three = 1 + 2;
    yield three * three;                                // line 7
  }
  default -> throw new IllegalStateException("Unknown day: " + day);
};

We can also let our IDE do the complete refactoring from the conventional switch statement to the switch expression with arrow notation:

Automatic replacement of “switch” statements by “switch” expressions
Automatic replacement of “switch” statements by “switch” expressions

Exhaustiveness Analysis for Enums

As the variable day is an enum, the compiler can recognize that we have covered all cases. Thus, we may omit the default case:

int numLetters = switch (day) {
  case MONDAY, FRIDAY, SUNDAY -> 6;
  case TUESDAY                -> 7;
  case THURSDAY, SATURDAY     -> (int) Math.pow(2, 3);
  case WEDNESDAY              -> {
    int three = 1 + 2;
    yield three * three;
  }
};

Our IDE does that for us as well:

Automatic removal of the “default” branch
Automatic removal of the “default” branch

The notation without a default case is shorter and assists us in future extensions of the enum. If we extend it – e.g., by a NEWDAY – the compiler will tell us that the switch expression is now incomplete:

Incomplete “switch” expression
Incomplete “switch” expression

So switch expressions can also make our code more robust.

For other selector types such as String or int, the compiler cannot check exhaustiveness. There, default is mandatory in a switch expression – otherwise, the compiler reports “the switch expression does not cover all possible input values”.

A switch statement (that is, a switch without a return value), on the other hand, may remain incomplete – unless it is a “modern” switch statement with pattern cases or a case null (see the next section).

Switch Since Java 21

With Java 21, JEP 441 (“Pattern Matching for switch”) extended switch a second time – on the same foundation you have seen in this article:

  • A case can carry a type pattern instead of a constant and bind the value directly to a variable: case String s -> …
  • case null catches a null selector, which until then always led to a NullPointerException.
  • With when, you narrow a case further (a so-called guard): case Integer i when i > 0 -> …
  • Enum constants may be qualified: case Day.MONDAY instead of case MONDAY.
  • Exhaustiveness analysis no longer applies only to enums but also to sealed classes and interfaces: If the switch covers all permitted subtypes, default is omitted just the same.

Selectors of type long, float, double, and boolean arrive with Primitive Types in Patterns, instanceof, and switch – in Java 27 as a fifth preview (JEP 532).

Summary

The arrow notation and the use as an expression with a return value allow a much more concise and less error-prone notation than before.

I recommend using the arrow notation as the default – in statements as well as in expressions. You only need the colon form for legacy code in which one case intentionally falls through to the next.

Switch expressions were first introduced in Java 12 as a preview feature. In the second preview in Java 13, the break keyword, initially used to return values, was replaced by yield. With JDK Enhancement Proposal 361, switch expressions were released as a final feature in Java 14 without any further changes.

Did this article answer your questions? Then I’d be happy about a review on my ProvenExpert profile – it helps other developers find this content.

👉 Leave a review

This subject in your own code?

You have read the article – in the training your team works with it. Over 2 days we go through the subjects on your own projects instead of constructed examples.

Hands-on, easy to understand, and directly applicable to your day-to-day project work. Instead of theory, I teach principles that help you write code that is better, more maintainable, and more performant in the long run.

Java 17 TrainingSee all trainings

Become a Better Java Developer

My free newsletter keeps you ahead. Modern Java: new versions & features, performance, and JVM insights – once a month.

Search