为什么 java switch 语句不能处理 null,因为它有一个“default”子句?
例如,如果您有类似的东西
switch(value){
case VAL1: do_something1(); break;
case VAL2: do_something2(); break;
default: do_something3();
}
“默认”不应该处理任何其他值,例如 null?
一如既往,在 JLS 中:
14.11。
声明switch
以下所有条件都必须为真,否则会出现编译时错误:
- ...
- 无开关标签为
。null
...
禁止使用作为开关标签可以防止编写永远无法执行的代码。如果 switch 表达式是引用类型,即null
或装箱基元类型或枚举类型,则如果该表达式在运行时计算结果为String
,则会发生运行时错误。在Java编程语言的设计者看来,这比默默地跳过整个null
语句或选择执行switch
标签(如果有)之后的语句(如果有)更好的结果。default
简而言之,这种设计选择是本着Java精神。
当 switch 表达式计算结果为
null
时抛出 NPE 的决定与 Java 中做出的其他决定类似,Java 总是更喜欢抛出异常,而不是以“明显”的方式静默处理 null
。一般规则似乎是,当有疑问时,Java 设计者会选择没有默认行为的选项。这具有在每个使用站点都需要样板代码的副作用。
有些人会认为这令人沮丧和不幸,但其他人不同意,认为这是一个更安全的决定。
对于另一个可能令人沮丧的示例,请参阅增强的 for 循环,如果集合是
null
,它也会抛出 NPE,而不是表现得好像集合为空。 JDK 库中还有更多示例,其中调用者必须检查所有边缘情况,以便能够将它们与“正常”情况统一处理。
作为第三个臭名昭著的例子,Java 的检查异常需要大量样板文件来处理调用堆栈深度的每个级别,并引诱经验不足的程序员陷入几种反模式。结果通常是吞掉异常、在日志中多次报告相同的异常、在错误的抽象级别上得到不一致处理的异常等。
这是根据定义。我不会在这方面浪费太多时间,因为它在规范中。
另一方面,我发现这实际上非常实用,因为在为 null 的情况下它没有关联的原始类型,所以我们不知道如何正确处理它。