Skip to main content

Week 9 Day 4 — Switch Expressions and Text Blocks

Goal

Today I want two 17-era syntax tools I will actually type in production: switch as an expression and text blocks.

Main questions:

  1. How does a switch expression differ from a statement?
  2. What did arrow cases change about fall-through?
  3. When do I need yield?
  4. What are text blocks for?
  5. What else did 21 add that I might name (sequenced collections)?

1. Switch as a value

HttpStatus status = switch (result) {
case PaymentAccepted a -> HttpStatus.OK;
case PaymentRejected r -> HttpStatus.PAYMENT_REQUIRED;
case PaymentPending p -> HttpStatus.ACCEPTED;
};

The switch is an expression. Every branch must produce a value (or throw). The compiler checks exhaustiveness for enums and sealed types.

Old statement switch with break still exists. I use expressions for mapping. I use statements when each branch is a sequence of void work.

Memory sentence:

Arrow switch does not fall through. Expression switch must cover every case.


2. Arrows vs colons

Colon cases fall through unless I break. That bug is ancient.

Arrow cases (->) do not fall through. One case, one body.

// statement, arrows, no fall-through
switch (code) {
case 404 -> log.warn("missing");
case 500 -> log.error("bug");
default -> log.info("other");
}

Multi-label: case 401, 403 -> ....

A block body of an expression uses yield:

int n = switch (status) {
case OPEN -> 1;
case CLOSED -> {
audit(status);
yield 0;
}
};

yield is not return. return leaves the enclosing method.


3. Null and patterns (21)

Classic switch on an object NPE’d on null. Pattern switches can have case null:

return switch (name) {
case null -> "unknown";
case String s when s.isBlank() -> "blank";
case String s -> s;
};

when is a guard. The case matches only if the pattern and the guard succeed.

I do not put business rules that hit the database in a guard. Guards stay cheap.


4. Text blocks

String sql = """
SELECT id, status
FROM orders
WHERE sku = :sku
""";

A text block is a """ string. The compiler strips a common indent (the leftmost non-blank column, aligned with the closing """). Newlines are part of the string.

Use for JSON fixtures, SQL, HTML snippets in tests. For user-facing HTML I still want a template engine.

I can interpolate with formatted:

String json = """
{ "sku": "%s", "qty": %d }
""".formatted(sku, qty);

Escape: \""" inside, or stripIndent facts I only mention if asked. Trailing \s keeps spaces the compiler would otherwise ignore.

Memory sentence:

Text blocks are multiline strings with incidental indent stripped. They are not a template engine.


5. Sequenced collections (21)

SequencedCollection adds getFirst(), getLast(), addFirst, reversed() on List, Deque, and linked sets/maps.

List<Order> last = orders.reversed(); // view, Java 21
Order newest = orders.getLast();

I name this if they ask “what is new in 21 besides virtual threads?” I do not rewrite every list.get(list.size()-1) in a fanfare.


6. Spring connection

  • Map domain sealed results to HttpStatus with a switch expression in a mapper, not a chain of if.
  • Text blocks in @DataJpaTest SQL or JSON for MockMvc.
  • Avoid text-block SQL concatenation for user input — still use bind parameters (:sku).

7. Common traps

Trap 1: Colon switch and a missing break.

Trap 2: return inside a switch expression block instead of yield.

Trap 3: Text block indent that includes the closing """ too far left, leaving extra spaces in SQL.

Trap 4: Building SQL with formatted from request strings. Bind parameters.

Trap 5: Non-exhaustive switch on an enum, relying on default that hides a new constant.


Practice Questions and Answers

Question 1

Switch expression vs statement?

Answer:

An expression produces a value; every branch must yield one (or throw), and enums/sealed types can be exhaustive. A statement performs work. Arrow cases do not fall through. Blocks in an expression use yield, not return.


Question 2

Why did Java add text blocks?

Answer:

So SQL, JSON, and HTML in source are readable without \n and +. The compiler removes a common indent. They are still String. They are not templates and they do not escape user input.


Question 3

What is a when guard?

Answer:

An extra boolean on a pattern case (case String s when s.isBlank()). The case matches only if both the pattern and the guard succeed. The next case can still match the same type.


Question 4

yield vs return in a switch?

Answer:

yield produces the switch expression’s value and stays in the method. return leaves the method. In an expression switch I yield.


Question 5

Name one Java 21 collections API besides virtual threads.

Answer:

Sequenced collections: getFirst, getLast, reversed on lists and related types. Small quality-of-life, not a new data structure.


Memory sentences

Arrow switch does not fall through. Expression switch must cover every case.

yield is for the switch. return is for the method.

Text blocks are multiline strings, not templates. Still bind SQL parameters.

Next: Week 9 Day 5 — Virtual Threads