Pra*_*ate 115 java language-design switch-statement
我只是想知道为什么Java 7 switch语句不支持一个null案例而是抛出NullPointerException?请参阅下面的注释行(示例摘自Java Tutorials文章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;
}
Run Code Online (Sandbox Code Playgroud)
这样可以避免if在每次switch使用之前进行空检查的条件.
Pau*_*ora 138
正如damryfbfnetsi 在评论中指出的那样,JLS§14.11有以下注释:
禁止
null用作开关标签可以防止编写永远不会执行的代码.如果switch表达式是引用类型,即String盒装基元类型或枚举类型,则表达式null在运行时求值时将发生运行时错误.在Java编程语言的设计者的判断中,这比默默地跳过整个switch语句或选择在default标签之后执行语句(如果有的话)(如果有的话)更好.
(强调我的)
虽然最后一句话超过了使用的可能性case null:,但这似乎是合理的,并提供了语言设计者的意图.
如果我们宁愿查看实现细节,Christian Hujer撰写的这篇博文有一些深刻的猜测,说明为什么null交换机不允许这样做(尽管它以交换机为中心enum而不是String交换机):
在引擎盖下,
switch语句通常会编译为tablesswitch字节代码.并且switch它的案例的"物理"论证是ints.要打开的int值是通过调用方法确定的Enum.ordinal().[...]序数从零开始.这意味着,映射
null到0不会是一个好主意.第一个枚举值的开关将与null无法区分.也许以1开始计算枚举的序数是个好主意.然而,它没有被定义为这样,并且这个定义不能改变.
虽然String交换机的实现方式不同,但enum交换机首先出现,并为引用类型在引用类型时应如何进行操作设置了先例null.
Zho*_*gYu 30
总的来说null是讨厌的处理; 也许更好的语言可以没有null.
您的问题可能会被解决
switch(month==null?"":month)
{
...
//case "":
default:
monthNumber = 0;
}
Run Code Online (Sandbox Code Playgroud)
kri*_*spy 23
它不漂亮,但String.valueOf()允许您在交换机中使用空字符串.如果找到null,则将其转换为"null",否则它只返回传递它的相同String.如果你没有"null"明确处理,那么它会去default.唯一需要注意的是,无法区分String "null"和实际null变量.
String month = null;
switch (String.valueOf(month)) {
case "january":
monthNumber = 1;
break;
case "february":
monthNumber = 2;
break;
case "march":
monthNumber = 3;
break;
case "null":
monthNumber = -1;
break;
default:
monthNumber = 0;
break;
}
return monthNumber;
Run Code Online (Sandbox Code Playgroud)
Pra*_*ate 15
NullPointerException下面的javap命令输出显示case根据switch参数字符串的哈希码选择,因此.hashCode()在空字符串上调用时会抛出NPE .
6: invokevirtual #18 // Method java/lang/String.hashCode:()I
9: lookupswitch { // 3
-1826660246: 44
-263893086: 56
103666243: 68
default: 95
}
Run Code Online (Sandbox Code Playgroud)
这意味着基于Can Java的hashCode的答案为不同的字符串产生相同的值?尽管很少见,但仍有两种情况可以匹配(两个字符串具有相同的哈希码)请参见下文
int monthNumber;
String month = args[0];
switch (month) {
case "Ea":
monthNumber = 1;
break;
case "FB":
monthNumber = 2;
break;
// case null:
default:
monthNumber = 0;
break;
}
System.out.println(monthNumber);
Run Code Online (Sandbox Code Playgroud)
javap为哪
10: lookupswitch { // 1
2236: 28
default: 59
}
28: aload_3
29: ldc #22 // String Ea
31: invokevirtual #24 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
34: ifne 49
37: aload_3
38: ldc #28 // String FB
40: invokevirtual #24 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
43: ifne 54
46: goto 59 //Default
Run Code Online (Sandbox Code Playgroud)
好吧,你可以看到只有一个案例被生成但有两个if条件来检查每个案例字符串的mach.实现此功能非常有趣和复杂的方式!
长话短说...(希望足够有趣!!!)
枚举首先在介绍了Java1.5的(Sep'2004)和错误请求允许在字符串开关被提起长回(1995年10月)。如果你看一下张贴在该bug的评论Jun'2004,它说,Don't hold your breath. Nothing resembling this is in our plans.看起来他们推迟(忽略)这个bug,并最终推出的Java 1.5中,他们推出了“枚举”与序同年从0开始,并决定(错过)不支持枚举为null。后来在Java1.7(Jul'2011)他们跟(强制)与String相同的原理(即,在生成字节码时,在调用hashcode()方法之前未执行空检查)。
因此,我认为它归结为以下事实:枚举首先出现,并且以序数从0开始执行,这是因为它们不能在切换块中支持空值,后来在使用String时,他们决定强制采用相同的原理,即不设置空值在开关块中允许。
TL; DR使用String,他们可以在实现Java代码到字节代码的转换时照顾NPE(由于试图为null生成哈希码而引起),但最终决定不这样做。
参考: TheBUG, JavaVersionHistory, JavaCodeToByteCode, SO
| 归档时间: |
|
| 查看次数: |
43606 次 |
| 最近记录: |