java switch null_java - 为什么String switch语句不支持null case?

java - 为什么String switch语句不支持null case?

我只是想知道为什么Java 7 if声明不支持switch情况而是抛出NullPointerException? 请参阅下面的注释行(示例摘自if上的Java Tutorials文章):

{

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条件。

9个解决方案

135 votes

正如damryfbfnetsi在评论中指出的那样,JLS§14.11有以下注释:

禁止使用String作为开关标签禁止编写永远不会执行的代码。 如果enum表达式是引用类型,即null或盒装基元类型或枚举类型,则如果表达式在运行时求值为Enum.ordinal(),则会发生运行时错误。 在Java编程语言的设计者的判断中,这比静默跳过整个String语句或选择在enum标签(如果有)之后执行语句(如果有)更好。

(强调我的)

虽然最后一句话超过了使用String的可能性,但这似乎是合理的,并提供了语言设计师的观点。意图。

如果我们宁愿查看实现细节,Christian Hujer撰写的这篇博文有一些深刻的猜测,说明为什么String不允许在交换机中使用(尽管它以enum交换机而不是null交换机为中心):

在引擎盖下,String语句通常会编译为tablesswitch字节代码。 并且"物理" 对enum及其案例的论据是nulls。 要打开的int值是通过调用方法Enum.ordinal()确定的。[...]序号从零开始。

这意味着,将String映射到enum不是一个好主意。 第一个枚举值的开关将与null无法区分。 也许在1开始计算枚举的序数是一个好主意。然而,它没有被定义为这样,并且这个定义不能改变。

虽然String交换机的实现方式不同,但enum交换机排在第一位,并为引用类型null时引用类型应如何工作设置了先例。

Paul Bellora answered 2019-07-02T02:10:51Z

25 votes

一般情况下,null处理起来很讨厌; 也许更好的语言可以没有null。

您的问题可能会被解决

switch(month==null?"":month)

{

...

//case "":

default:

monthNumber = 0;

}

ZhongYu answered 2019-07-02T02:11:25Z

23 votes

它不漂亮,但String.valueOf()允许您在交换机中使用空字符串。 如果找到null,则将其转换为"null",否则它只返回您传递的相同String。 如果你没有明确地处理"null",那么它将转到default。唯一需要注意的是,无法区分字符串"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;

krispy answered 2019-07-02T02:11:57Z

14 votes

这是为了回答它抛出case的原因

下面的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

}

这意味着基于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);

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

好吧,你可以看到只有一个案例被生成但有两个if条件来检查每个案例字符串的马赫。实现此功能非常有趣和复杂的方式!

Prashant Bhate answered 2019-07-02T02:13:00Z

4 votes

长话短说...(希望足够有趣!)

Enum最初是在Java1.5中引入的(Sep' 2004),并且要求允许切换字符串的错误已经提交了很长时间(Oct' 95)。 如果你看看Jun' 2004上发布的关于该bug的评论,它就说Don't hold your breath. Nothing resembling this is in our plans.看起来他们推迟(忽略)了这个bug,并最终在他们引入的同一年推出了Java 1.5' enum' 顺序从0开始并决定(错过)不支持枚举的null。 后来在Java1.7(Jul' 2011)中,他们跟随(强制)使用String的相同哲学(即在生成字节码时,在调用hashcode()方法之前没有执行空检查)。

所以我认为它归结为enum首先出现的事实,并且它的序数从0开始实现,因为它们不能在switch块中支持null值,后来使用String它们决定强制使用相同的哲学,即null 开关块中不允许的值。

TL; DR使用String,他们可以处理NPE(由尝试生成hash的hashcode引起),同时实现java代码到字节码转换,但最终决定不这样做。

参考:错误,JavaVersionHistory,JavaCodeToByteCode,所以

sactiw answered 2019-07-02T02:14:06Z

1 votes

根据Java Docs:

交换机使用byte,short,char和int原始数据  类型。 它也适用于枚举类型(在枚举类型中讨论),   String类,以及一些特定的包装类   原始类型:字符,字节,短整数和整数(在   数字和字符串)。

由于null没有类型,并且不是任何实例,因此它不适用于switch语句。

BlackHatSamurai answered 2019-07-02T02:14:51Z

0 votes

答案很简单,如果您使用带引用类型的开关(例如盒装基元类型),如果表达式为null,则会发生运行时错误,因为取消装箱会抛出NPE。

所以无论如何都无法执行null(这是非法的);)

amrith answered 2019-07-02T02:15:27Z

0 votes

我同意@Paul Bellora的答案中[https://stackoverflow.com/a/18263594/1053496]的深刻见解(引擎盖下......)。

我从经验中找到了另一个原因。

如果' case' 可以为null表示switch(变量)为null,只要开发人员提供匹配的' null' 那么我们可以说它很好。 但是,如果开发人员没有提供任何匹配的“空”,将会发生什么? 案件。 然后我们必须将其与默认值相匹配。 在默认情况下可能不是开发人员打算处理的情况。 因此匹配' null' 默认情况下可能会导致令人惊讶的行为'因此,投掷NPE' 将使开发人员明确处理每个案例。 我发现在这种情况下投掷NPE非常周到。

nantitv answered 2019-07-02T02:16:14Z

0 votes

使用Apache StringUtils类

String month = null;

switch (StringUtils.trimToEmpty(month)) {

case "xyz":

monthNumber=1;

break;

default:

monthNumber=0;

break;

}

bhagat answered 2019-07-02T02:16:47Z

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Javaswitch case语句是一种常用的控制流语句,用于基于不同的输入值执行不同的操作。它由switch关键字、一个括号和一个或多个case语句组成。在Java中,switch case语句的用法如下所示: switch(expression){ case value1: // 执行语句1 break; case value2: // 执行语句2 break; // 可以有任意数量的case语句 default: // 执行默认语句 } 在上面的代码中,expression表示要测试的表达式的值。每个case语句后面跟着一个值(value),如果expression的值与某个case语句的值相等,则执行相应的语句。如果没有匹配的case语句,那么执行default语句。 例如,在下面的示例中,根据num的值执行不同的操作: public class SwitchDemo { public static void main(String[] args) { int num = 3; switch (num) { case 1: System.out.println("One"); break; case 2: System.out.println("Two"); break; case 3: System.out.println("Three"); break; default: System.out.println("Not found"); } } } 在这个示例中,num的值为3,因此会执行case 3下的语句,输出"Three"。如果num的值为1,则会执行case 1下的语句,输出"One"。如果num的值没有与任何case语句匹配,那么会执行default语句,输出"Not found"。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Java switch case 语句](https://blog.csdn.net/weixin_47477471/article/details/129334643)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Java--switch case 语句](https://blog.csdn.net/weixin_44688529/article/details/128626327)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值