超出包含 switch 表达式的返回值

19

我正在使用Java 12中的switch表达式¹将字符串转换为HTTP方法

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;
              }
          });
}

我想警告默认分支中不支持的方法并返回null(然后将其包装在Optional中)。

但是上面的代码会导致编译错误:

返回超出了封闭的switch表达式

我该如何使其编译通过?


为了完整起见,这是RequestMethod枚举的定义:

enum RequestMethod {GET, PUT, POST, HEAD}

Java 12引入了预览功能的switch表达式


为什么不使用 RequestMethod.valueOf(methodStr.strip().toUpperCase(Locale.ROOT)) - VGR
@VGR:因为那可能会抛出IllegalArgumentException异常。但是问题中的代码只是一个示例,展示编译器错误“Return outside of enclosing switch expression”的产生方式。 - Matthias Braun
5
表达式(包括switch表达式)必须要么产生一个值,要么抛出异常。你不能breakcontinue或者return到其他上下文中,除了正常完成(带有一个值;在12中为break value,在13中改为yield value)或抛出异常的情况。 - Brian Goetz
1个回答

39

在Java 13中使用yield

在Java 13中,switch表达式使用新的受限标识符¹yield从块中返回一个值:

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;
            }
        });

在Java 12中使用break

在Java 12中,开关表达式使用break来从块中返回一个值:

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;
            }
        });

¹ 用户skomisa指出,yield 不是关键字


14
感谢您的教导:现在是时候密切关注这些新的Java版本了。它们带来了意想不到的内容,超越了我的思维范畴。 - GhostCat
严谨地说,关于“...新关键字yield...”,Java 13的建议JLS(Java语言规范)已经包含了JEP 354(“Switch Expressions”)的更改,并明确指出yield不是关键字。来自第3.9节关键字的说明:“受限标识符var和yield不是关键字...在yield语句中,yield具有特殊含义...”。值得注意的是,相比之下,break是一个关键字。在这个阶段添加新的关键字到Java中(尤其是yield)可能会带来很大的问题... - skomisa
因此,yield 应该被描述为“受限标识符”,而不是“关键字”。您可以轻松验证 yield 不是关键字,因为在 Java 13 中,在 Eclipse 2019-09 上编译 int yield = 0; 是没有问题的。相比之下,int break = 0; 则会出现错误:“Syntax error on token "break", invalid VariableDeclarator”。 - skomisa
Java(JEP / JLS)文档中的又一个不一致之处:虽然“break”用于从switch表达式中产生值,但相应的JEP文档表示,switch表达式可以突然完成abruptly,这意味着在此处也必须使用“return”。 - Giorgi Tsiklauri
@GiorgiTsiklauri 这行代码可能解释了这个不一致性:表达式突然结束的唯一原因是抛出了异常,可能是通过给定值进行的抛出(§14.18),也可能是运行时异常或错误(§11(异常),§15.6)。 - Michael Pfaff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接