18

I'm using a switch expression¹ in Java 12 to convert a string to a HTTP method:

static Optional<RequestMethod> parseRequestMethod(String methodStr) {
    return Optional.ofNullable(
          switch (methodStr.strip().toUpperCase(Locale.ROOT)) {
              case "GET" -> RequestMethod.GET;
              case "PUT" -> RequestMethod.PUT;
              case "POST" -> RequestMethod.POST;
              case "HEAD" -> RequestMethod.HEAD;

              default -> {
                  log.warn("Unsupported request method: '{}'", methodStr);
                  return null;
              }
          });
}

I'd like to warn about the unsupported method in the default branch and return null (which is then wrapped in an Optional).

But the code above causes a compiler error:

Return outside of enclosing switch expression

How do I get this to compile?


For completeness, here's the definition of the RequestMethod enum:

enum RequestMethod {GET, PUT, POST, HEAD}

¹ switch expressions were introduced in Java 12 as a preview feature.

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
  • Why not use `RequestMethod.valueOf(methodStr.strip().toUpperCase(Locale.ROOT))`? – VGR Jun 28 '19 at 14:24
  • @VGR: Because that can throw an IllegalArgumentException. But the code in the question is only an example showing how the compiler error "Return outside of enclosing switch expression" can occur. – Matthias Braun Jun 28 '19 at 18:07
  • 5
    Expressions (including switch expressions) must either yield a value, or throw. You cannot `break`, `continue`, or `return` to other contexts, other than completing normally (with a value; `break value` in 12, changed to `yield value` in 13) or throwing. – Brian Goetz Jun 30 '19 at 16:12

1 Answers1

38

use yield in Java 13

In Java 13, switch expressions use the new restricted identifier¹ yield to return a value from a block:

return Optional.ofNullable(
        switch (methodStr.strip().toUpperCase(Locale.ROOT)) {
            case "GET" -> RequestMethod.GET;
            // ... rest omitted

            default -> {
                log.warn("Unsupported request method: '{}'", methodStr);
                // yield instead of return
                yield null;
            }
        });

use break in Java 12

In Java 12, switch expressions use break to return a value from a block:

return Optional.ofNullable(
        switch (methodStr.strip().toUpperCase(Locale.ROOT)) {
            case "GET" -> RequestMethod.GET;
            // ... rest omitted

            default -> {
                log.warn("Unsupported request method: '{}'", methodStr);
                // break instead of return
                break null;
            }
        });

¹ yield is not a keyword, as helpfully pointed out by user skomisa.

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
  • 13
    Thank for teaching me: it is time to closely closely observe these new Java releases. They yield unexpected content, which breaks out of my mind. – GhostCat Jun 28 '19 at 12:28
  • Being pedantic, regarding _"...the new keyword yield..."_, the proposed JLS for Java 13 which incorporates changes for JEP 354 ("Switch Expressions") explicitly states that `yield` is not a keyword. From [section 3.9 Keywords](https://docs.oracle.com/javase/specs/jls/se13/preview/switch-expressions.html#jep354-3.9): _"The restricted identifiers var and yield are not keywords....yield has special meaning in a yield statement..."_. It's also worth noting that in contrast, `break` is a keyword. Adding new keywords to Java at this stage (and `yield` in particular) might be highly problematic... – skomisa Sep 22 '19 at 04:05
  • ... So presumably `yield` should be described as a _"restricted identifier"_ rather than a _"keyword"_. You can easily verify that `yield` is not a keyword because `int yield = 0;` compiles just fine on Java 13 in Eclipse 2019-09. In contrast, `int break = 0;` gives the error _Syntax error on token "break", invalid VariableDeclarator_ – skomisa Sep 22 '19 at 04:07
  • Yet another inconsistency in Java (JEP/JLS) documentation: while it's true, that `break` is used to yield a value from switch expressions, [corresponding JEP](https://openjdk.java.net/jeps/325)'s document says, that switch expressions can complete [abruptly](https://docs.oracle.com/javase/specs/jls/se16/html/jls-14.html#jls-14.1), which means - `return` must also be working here.. – Giorgi Tsiklauri Sep 03 '21 at 01:00
  • @GiorgiTsiklauri this line might explain that inconsistency: The only reason an expression can complete abruptly is that an exception is thrown, because of either a throw with a given value (§14.18) or a run-time exception or error (§11 (Exceptions), §15.6). – Michael Pfaff Aug 31 '23 at 19:34