为什么 String switch 语句不支持 null 情况?

2022-01-19 00:00:00 language-design switch-statement java

我只是想知道为什么 Java 7 switch 语句不支持 null 情况而是抛出 NullPointerException?请参阅下面的注释行(示例取自 关于 的 Java 教程文章切换):

I am just wondering why the Java 7 switch statement does not support a null case and instead throws NullPointerException? See the commented line below (example taken from the Java Tutorials article on switch):

{
    String month = null;
    switch (month) {
        case "january":
            monthNumber = 1;
            break;
        case "february":
            monthNumber = 2;
            break;
        case "march":
            monthNumber = 3;
            break;
        //case null:
        default: 
            monthNumber = 0;
            break;
    }

    return monthNumber;
}

这将避免在每次 switch 使用之前进行空检查的 if 条件.

This would have avoided an if condition for null check before every switch use.

推荐答案

作为damryfbfnetsi 在评论中指出,JLS §14.11 有以下注释:

As damryfbfnetsi points out in the comments, JLS §14.11 has the following note:

禁止使用 null 作为开关标签可以防止编写永远无法执行的代码.如果 switch 表达式是引用类型,即 String 或装箱的原始类型或枚举类型,则如果表达式求值,则会发生运行时错误null 在运行时.在 Java 编程语言的设计者看来,这比默默地跳过整个 switch 语句或选择执行 default 之后的语句(如果有)更好的结果 标签(如果有).

The prohibition against using null as a switch label prevents one from writing code that can never be executed. If the switch expression is of a reference type, that is, String or a boxed primitive type or an enum type, then a run-time error will occur if the expression evaluates to null at run time. In the judgment of the designers of the Java programming language, this is a better outcome than silently skipping the entire switch statement or choosing to execute the statements (if any) after the default label (if any).

(强调我的)

虽然最后一句跳过了使用 case null: 的可能性,但它似乎是合理的,并提供了对语言设计者意图的看法.

While the last sentence skips over the possibility of using case null:, it seems reasonable and offers a view into the language designers' intentions.

如果我们更愿意看一下实现细节,这篇博文Christian Hujer 对为什么在开关中不允许使用 null 有一些有见地的推测(尽管它以 enum 开关而不是 String 开关为中心):

If we rather look at implementation details, this blog post by Christian Hujer has some insightful speculation about why null isn't allowed in switches (although it centers on the enum switch rather than the String switch):

在底层,switch 语句通常会编译为tablesswitch 字节码.而物理"switch 的参数及其案例是 ints.要打开的 int 值是通过调用方法 Enum.ordinal() 确定的.[...] 序数从零开始.

Under the hood, the switch statement will typically compile to a tablesswitch byte code. And the "physical" argument to switch as well as its cases are ints. The int value to switch on is determined by invoking the method Enum.ordinal(). The [...] ordinals start at zero.

这意味着,将 null 映射到 0 并不是一个好主意.第一个枚举值的开关与 null 没有区别.也许从 1 开始计算枚举的序数是个好主意.但是它并没有这样定义,而且这个定义不能更改.

That means, mapping null to 0 wouldn't be a good idea. A switch on the first enum value would be indistinguishible from null. Maybe it would've been a good idea to start counting the ordinals for enums at 1. However it hasn't been defined like that, and this definition can not be changed.

虽然 String 开关 实现方式不同,但 enumswitch 最先出现,并开创了在引用为 null 时打开引用类型的行为方式的先例.

While String switches are implemented differently, the enum switch came first and set the precedent for how switching on a reference type should behave when the reference is null.

相关文章