何时在Java中使用switch语句

我很欣赏任何可以通过switch语句完成的事情都可以通过if else语句来完成。

但是,当有人应该使用开关而不是if else的声明时,是否有风格规则。

嗯,在我看来,在许多情况下, switch感觉比在if / else if梯子上“更轻”。 基本上,您的代码方式中没有大括号和括号的语法。 话虽这么说, switchinheritance了C的语法。 这意味着除非你引入新的块,否则你有变量而且只有一个变量范围。

仍然,编译器能够将switch语句优化为查找表,并在处理枚举时对文字执行编译时检查。 所以,我建议如果你正在处理数字或枚举类型,通常最好使用switch if / else if

Switch在清晰度方面具有一个优势:

 switch (i) { case 1: // do something break; case 2: case 4: // do something break; case 5: // do something break; } 

如果2和4的代码相同,则可能比以下更清楚:

 if ( i == 1 ) { // do something } if ( (i == 2) || (i == 4) ) { // do something } if ( (i == 5 ) { // do something } 

您(或其他程序员)也可以更容易地分割出2个4个案例。

我使用switch语句作为枚举,如果else if if else语句,它更具可读性。 但是,您应该尽量避免在OO设计中进行此类检查。

当您打开基元/枚举/包装类型的不同值时,可以使用switch语句。 (并非所有原始/包装类型,只有受支持的类型 – byte,short,char,int)。

如果/ else处理其余的。

例如,说起来更美观:

 int i = getValueOfI(); switch (i) { case 1: // do something break; case 2: // do something break; 

等等

 if (i == 1) { } else if (i == 2) { }... 

对于大量的案件。 但是你不能打开字符串,函数值或复杂的条件,所以如果你需要做任何这些,那么你就会被if / else所困扰。

在个人情况下,我用来发现这两种结构有点过于程序化。 虽然它可能被视为OO extermism,但我使用包含if的每个case的内部接口实例的Map。 我认为它允许更好的代码隔离。 但是,为了回答你的问题,当我遇到真正重叠的情况时,我只使用开关(我不使用break语句)。 不幸的是,它实际上不是一个可维护的代码块。

我建议简单的规则:

当您有至少2个选项来区分,当数据类型可用于交换机以及所有选项具有常量值时,请始终使用switch

有三个很好的理由。 一,在大多数情况下, switchif / else级联更快。 二,它使代码的意图更清晰。 三,哦,如此糟糕的被遗忘的break困境是一个较小的邪恶,而不是巨大的if / else级联,因为有人忘记了else而意外破坏。

Java VM实际上支持两种不同类型的交换机:tableswitch和lookupswitch指令。 如果所有case常量都在一个窄范围内,则tableswitch由编译器生成,否则它会生成一个lookupswitch。 对于具有许多情况的大型switch语句,tableswitch比lookupswitch更有效。 lookupswitch通常通过某种forms的二进制搜索来实现。

对我来说有两个因素:

可读性以及是否要使用值或条件范围来决定某些内容(在switch语句中,您只能使用单个整数或枚举值)。

首先,switch语句必须是可用的。 如果开关基于变量的值,则可以使用它。 如果它基于一个复杂的AND / OR / NOT布尔表达式,它对每个条件都有所不同,那么根本就不能使用它。

话虽如此,如果它适用,并且至少有2个案例,那么我使用开关。 它更容易扩展,更易于阅读和检查。

切换和枚举。

如果您正在测试的枚举值因任何原因合法地为null ,则将其置于switch语句中将生成NullPointerException。 如果不看字节代码,它会有点莫名其妙。

解释:枚举是1.5中引入的语法糖。 Switch语句仍适用于good-ole int,但它使用的值是分配给enum的序数。 为了得到序数,枚举值必须是非空的。

另一方面, if statement很乐意接受枚举值的null ,并且在没有NPE的情况下测试失败。

也许有点offtopic,但如果我回答标题中的问题,那么我会说你不应该在所有情况下使用switch,其中case表示某个对象的状态。 在这些情况下,状态模式是更漂亮的解决方案。

我总是发现java switch语句没有我想要的那么强大。 在他的最后一个版本中, lambdaj通过巧妙地使用闭包和Hamcrest匹配器来实现它 。

例如, lambdaj Switcher允许实现策略模式。 假设您必须根据要排序的列表的某些特征在三种排序算法之间切换。 特别假设我们有一个专门用于字符串的算法:

 public List sortStrings(List list) { // a sort algorithm suitable for Strings } 

另一个适用于不超过100个项目的小型列表:

 public List sortSmallList(List list) { // a sort algorithm suitable for no more than 100 items } 

更通用的一个:

 public List sort(List list) { // a generic sort algorithm } 

给定这3种排序方法,可以创建一种策略,以下面的声明方式选择最合适的策略:

 Switcher> sortStrategy = new Switcher>() .addCase(having(on(List.class).get(0), instanceOf(String.class))), new Closure() {{ of(this).sortStrings(var(List.class)); }}) .addCase(having(on(List.class).size(), lessThan(100))), new Closure() {{ of(this).sortSmallList(var(List.class)); }}) .setDefault(new Closure() {{ of(this).sort(var(List.class)); }}); 

并通过调用Switcher使用最佳可用算法对列表进行排序:

 List sortedList = sortStrategy.exec(list, list); 

答案取决于您正在做什么以及选择的分布。

如果一个条件占优势,那么if / then是合适的。

 if (i == 1){ //do something }else if (i == 2){ // do something else } 

如果条件均匀分布,则编译器中的优化将提供性能优势。 随着可能选择的数量增加,这种性能差异变得更加明显。

 switch (i) { case 1: // do something break; case 2: // do something else break; .... case N: // do yet something else break; } 

也就是说,如果性能不重要,那么你最喜欢的是你最喜欢的(可维护和最容易编写)。

另一方面,如果您的代码位于性能非常重要的热点,那么您应该使用交换机。

对于“非常大”的条件,Mario的lambdaj切换器的例子非常酷,并且在初始化时要小心,这将导致非常高的性能。 它与优化器生成的代码非常相似。 我会定义“非常大”,因为当选项的数量很大或足够复杂以使其值得输入时,并且当后续开发人员试图通过代码时值得支持混淆。 (注释你的代码,为什么你拥有这一切!)。

如果你有太多的条件来检查类似的类型,你可以去切换。

与其他语言(如C或C ++)一样,如果要将给定变量与可能值列表进行比较并根据这些值执行操作,则switch语句非常有用。 它比if else语句更为简洁。

我同意x4u的回答 。

此外还有另一个未提及的实例,但是,我认为最好使用ifelse块而不是switch :当使用if块测试每个case块中的附加条件时。 我在现有代码中一直看到这种混合物。

例如,我刚刚看到这个代码有一个字符串typeswitch ,然后在两个case语句中使用if检查第二个字符串extension

  public abstract class Temp { boolean valid; public Temp() { String type = getType(); String extension = getFilenameExtension(); switch(type) { case "Image File": { if(!".jpg".equals(extension) && !".png".equals(extension)) { warnWrongImageFormat(); valid = false; } break; } case "Zip File": { if(!".zip".equals(extension)) { warnWrongZipFormat(); valid = false; } break; } default: { valid = true; break; } } } abstract String getType(); abstract String getFilenameExtension(); abstract void warnWrongImageFormat(); abstract void warnWrongZipFormat(); } 

相反, if else这样做的if将其减少为一个更清洁,更简单

 public abstract class Temp { boolean valid; public Temp() { String type = getType(); String extension = getFilenameExtension(); valid = true; if("Image File".equals(type) && !".jpg".equals(extension) && !".png".equals(extension)) { warnWrongImageFormat(); valid = false; } else if("Zip File".equals(type) && !".zip".equals(extension)) { warnWrongZipFormat(); valid = false; } } abstract String getType(); abstract String getFilenameExtension(); abstract void warnWrongImageFormat(); abstract void warnWrongZipFormat(); } 

Switch有两个相关的缺点:

  • 它仅限于原始类型和枚举
  • 你必须记住“rest”,这可能导致不那么明显的错误

通常,切换是OO设计不佳的标志,因为您最好使用多态。

切换的唯一可能优点是,它更具可读性。 但是

 switch (i) { case 1: // do something break; case 2: // do something break; } 

比这更具可读性:

 if (i == 1) //do something else if (i == 2) // do something else 

我会说:不! 你不会有开关的缺点。

我的建议:尽量避免转换。