0

Java 14 standardized switch expression and since Java 17 they have enhanced the switch expression to include pattern matching.

Is there any guideline to when one should be using switch statement vs switch expression.

2
  • 1
    nipafx.dev/java-switch
    – Asmir
    Commented Jul 7 at 13:53
  • 1
    well... an expression returns a value, a statement doesn't... if you need a value, use switch expression; if you do not need a value, use switch statements (similar to conditional operator - ternary operator ?: - and if-else statement) Not to be confused with switch-rule vs. switch-block-statement
    – user85421
    Commented Jul 7 at 16:30

1 Answer 1

1

I think you're using the wrong words, there. Based on the notion that if you know what those terms meant you wouldn't be asking it; it'd be obvious.

An expression has a value. A statement does not.

When do you use one or the other? Well, when you need the result of the entire switch block to be 'to calculate a value' then expression, otherwise, statement. Example:

int wheels = switch (vehicleType) {
  case MOTORCYCLE, BICYCLE -> 2;
  case CAR -> 4;
  case CONSTRUCTION_TRUCK -> 6;
};

This construct has the considerable advantage that it demands completeness: If vehicleType is an expression of type VehicleType, and that is an enum and we covered all 4 possible values - the above compiles. But if, for example, MOPED is an option, the above will be an instant compiler error: You need to cover all the cases (after all, what should happen otherwise?). There's default ->, and if you want to opt into 'I just want an exception if an uncovered case occurs' you can simply add:

default -> throw new IllegalStateException("Not expected here: " + vehicleType);

However, I think you might be confused. Because there's a lot more to switch than just 'statement' v 'expression'. There are at least 3 dimensions involved:

Statement v Expression

In the past, switches simply couldn't themselves have a value. You had to do stuff like:

int wheels;
switch (vehicleType) {
  case BICYCLE:
  case MOTORCYCLE:
    wheels = 2;
    break;
  ... and so on
}

Which is annoying - it's kinda ugly, if you forget break; it really goes badly, the compiler doesn't help you with forgotten elements, and even if you cover it all, the compiler will complain that wheel "might not be set".

Hence, your first answer: If you can replace a statement with an expression you should always do that, they are strictly superior.

You don't have to write single expressions; you can write a block; you then use the yield keyword to provide the value instead. Thus, this:

case CAR -> 4;

and this:

case CAR -> {
  yield 4;
}

are the same thing. But you can add more stuff to the second form, so use that only if you have more stuff to do.

Arrow v colon

The arrow notation is new; the colon notation still works and has always worked. In fact, to highlight how 'arrow v colon' and 'expression v statement' are unrelated updates, you don't even have to use arrows in order to have a switch expression - that yield keyword can be used in colon-style switched just the same! (EDIT: This used to say 'arrow notation required' which isn't true; thanks to an observant @user85421 this has now been corrected).

The key difference, other than using an -> instead of a :, is that colon-notation 'falls through' (unless you end the body with a break;) and does not require braces, whereas arrow notation does not fall through and requires braces unless the body fits in a single line, the same way lambda syntax works (where braces can be omitted only if the 'body' is a single expression or a single statement).

You should use arrow notation unless fall-through is desired. Which it very rarely is, so you should virtually always use arrow notation!

NB: You might be wondering: If colon notation is so useless, why does java have it in the first place? Stupid design? - Well, maybe, but the reason java has it, is because C had it, and one of java's design goals was for arithmetic code to basically be straight copy-pastable from C to java, and for the syntax in general to be familiar and comfortable to C coders. Which means java has copied over a few, let's charitably call them, uh, odd, language design choices. Point is, it worked. Java is one of the very few languages that is as/more popular than the language it was designed to leech users off of. Scala and Kotlin certainly haven't managed to do to java what java did to C, for example.

pattern matching

This requires arrow notation if you want to use it - but, the thing that is in between case and -> can be a lot more than simply a value (case 4 -> - that's simply a value). You can pattern match. You can write, for example:

record Point(int x, int y) {}

void printPoint(Point p) {
  switch (p) {
    case Point(x, y) when x > 100 -> System.out.printf("[Far out, %d]", y);
  }
}

When do you use that? When... whenever it seems useful. Like most coding constructs the lang spec does not proscribe a limited domain for its intended use. There are style guides, but style guides in java land are quite old and simply haven't been updated. For example, most style guides require that you brace up all while, if, etcetera. However, they do not have the same requirements for lambdas. So, in most style guides, this is okay:

list.stream().map(x -> x.foo().bar()).filter(Bar::isNice).toList();

But this is not:

if (list.isEmpty()) throw new IllegalArgumentException("Empty list");
// style violation: Should have braces!

Which seems on the surface to be utter lunacy, and indeed if you read up on the style guide's underlying principles, it is lunatic: Every reason stated for why braces are required are even worse for lambda syntax! Clearly then either the style guide is outdated and should 'demand braces' for all lambdas, or, its principles are overwrought and 'ALWAYS use braces' is bad style. Opinion: It is. That second snippet is fine, 'always braces' is a common style principle that was always wrong and should, definitely in light of lambda syntax, be abolished.

2

Not the answer you're looking for? Browse other questions tagged or ask your own question.