我认为这可以通过语句的JLS确定赋值规则(JLS 16.2.9)来解释,该规则声明如下:switch
“V 在 switch 语句之后 [un]assigned,如果以下所有情况都为真:
- 开关块中存在默认标签,或者在开关表达式之后 [un]分配 V。
如果我们随后将其应用于名义值,即方法的返回值,我们可以看到,如果没有分支,则该值在名义上是未赋值的。V
default
还行。。。我正在推断明确的赋值规则来涵盖返回值,也许它们没有。但是,我无法在规范中找到更直接的东西并不意味着它不存在:-)
编译器必须给出错误还有另一个(更合理的)原因。它源于 (JLS 13.4.26) 的二进制兼容性规则,其中声明如下:enum
“从枚举类型添加或重新排序常量不会破坏与预先存在的二进制文件的兼容性。
那么,在这种情况下,这如何适用呢?假设允许编译器推断OP的示例switch语句总是返回某些内容。如果程序员现在更改 了 添加一个额外的常量,会发生什么情况?根据JLS二进制兼容性规则,我们没有破坏二进制兼容性。然而,包含该语句的方法现在可以(取决于其参数)返回未定义的值。不能允许发生这种情况,因此开关必须是编译错误。enum
switch
在Java 12中,他们引入了对switch的增强,其中包括switch表达式。这与在编译时和运行时之间更改的枚举遇到相同的问题。根据JEP 354,他们按如下方式解决了这个问题:
开关表达式的情况必须是详尽无遗的;对于所有可能的值,必须有一个匹配的开关标签。(显然,switch 语句不需要详尽无遗。
在实践中,这通常意味着需要一个默认条款;但是,对于涵盖所有已知常量的枚举开关表达式,编译器会插入一个默认子句,以指示枚举定义在编译时和运行时之间已更改。依靠这种隐式默认子句插入可以使代码更加健壮;现在,当重新编译代码时,编译器会检查是否显式处理了所有情况。如果开发人员插入了一个显式的默认子句(就像今天的情况一样),则可能的错误将被隐藏。
唯一不清楚的是隐式默认子句实际上会做什么。我的猜测是,它会引发一个未经检查的异常。(截至目前,Java 12 的 JLS 尚未更新以描述新的开关表达式。