何时在Java中使用switch语句

18
我很欣赏任何可以用switch语句完成的事情,都可以用if else语句完成。但是,何时应该使用switch而不是if else语句有没有样式规则呢?

3
当你不想惹恼下一个开发者,因为他必须要维护你代码中的100个 if/else 语句时。 - George Johnston
6
我不知道...我认为如果在一个开关中出现100个案例,我会感到非常烦恼。 :-) 这似乎是设计不良的味道。 - cjstehno
永远因为更快而选择:https://dev59.com/AXI95IYBdhLWcg3w7StZ - Ciro Santilli OurBigBook.com
17个回答

18

在我看来,在很多情况下,switchif/else if更“轻量级”,基本上你的代码中没有太多大括号和括号。尽管如此,switch继承了C语言的语法规则。这意味着你只有在引入新块时才会有break和单一变量范围。

尽管如此,编译器能够将switch语句优化为查找表,并在处理枚举类型时执行编译时检查。因此,如果你正在处理数字或枚举类型,通常建议使用switch而不是if/else if


2
顺便说一句,在JDK7中,switch语句中可以使用字符串。 - basszero
@basszero:这是最终版吗?据我所知,它还没有最终决定。 - BalusC

12

就清晰度而言,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 这两种情况拆分出来也更容易。


1
另一方面,对于常见情况,您需要拼写每个单独的值,而不能编写 else if (i % 2 == 0)。有时我会想念 VB 的 Select Case :-) - Joey

5

我使用switch语句来处理枚举类型,这比if else if else if语句更易读。然而,在面向对象的设计中,应该尽量避免这样的检查。


4

当你需要根据不同的原始/枚举/包装类型的值进行切换时,可以使用switch语句。(并非所有的原始/包装类型都支持,只有byte、short、char和int类型支持)

其余情况可以使用if / else语句。

例如,更美观的写法是:

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

etc.

than

if (i == 1) {

} else if (i == 2) {

}...

对于大多数情况,使用if/else语句是可以的。但是如果您需要切换字符串、函数值或复杂条件,那么您只能使用if/else语句。


1
我并不完全相信它在美学上更加令人愉悦 - 这有点取决于你习惯什么。使用 switch 的问题在于很容易忘记 break 语句。 - Dan
1
@Dan:我已经养成了一种习惯,总是将casebreak成对输入。这样我就不会忘记它们。但我同意这并不太好看。虽然可能没有多少人在这方面争论 :-) - Joey
至少在if-else语句中,你有语法来帮助你——也许在switch语句中的默认情况下,在匹配一个case之后应该加上break。 - Dan

3

个人而言,我发现这两种结构有点过程化。虽然这可能被视为面向对象的极端主义,但我通常会使用一个Map,其中包含每个if情况下的内部接口实例。我认为这样可以更好地隔离代码。然而,要真正回答你的问题,只有在有真正重叠的情况下(那时我不使用break语句),我才使用switch。不幸的是,这真的不是可维护的代码块。


我完全同意您使用switch语句处理重叠代码的观点。在我看来,switch语句需要完全不同的思考方式,与“if..else if”语句不同。您可以使用“case <value>:”来选择代码块中一个case的起始点,然后使用break来开始一个全新的代码块。对我而言,这种思考方式唯一的问题是,您不能为每个“break块”设置重复的case。 - Adi Bradfield

3
我建议一个简单的规则:
当您有至少两个要区分的选项,数据类型可用于 switch 且所有选项都具有常量值时,始终使用 switch。
有三个好理由。首先,在大多数情况下,switch 比 if/else 级联更快。其次,它使代码的意图更清晰。第三,被遗忘的 break 困境比因为某人忘记 else 而意外中断的巨大 if/else 级联更小。
Java VM 实际上支持两种不同类型的 switch:tableswitch 和 lookupswitch 指令。如果所有 case 常量都在一个狭窄的范围内,则编译器将生成 tableswitch,否则它将生成 lookupswitch。对于具有许多 case 的大型 switch 语句,tableswitch 比 lookupswitch 更有效。lookupswitch 通常是通过某种形式的二进制搜索实现的。

完全同意,除了忘记 break 和忘记 else。我认为不能争辩哪个比另一个更有可能。 - Kirby

2

对我来说有两个因素:

易读性以及您是想使用数值范围还是条件来做出决定(在switch语句中,您只能使用单个整数或枚举值)。


同意,任何需要数值范围的东西都需要一个if语句。 - David R Tribble

1

我一直觉得Java的switch语句不够强大。在他的最新版本中,lambdaj通过巧妙地使用闭包和Hamcrest匹配器实现了它

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

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

另一个适用于小型列表(不超过100个项目)的良好解决方案:

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

还有更通用的一个:

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

鉴于这三种排序方法,可以通过以下声明方式创建选择最合适的策略:

Switcher<List<T>> sortStrategy = new Switcher<List<T>>()
    .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<T> sortedList = sortStrategy.exec(list, list);

+1:这看起来很酷。Java的switch语句仍然如此薄弱,让我感到惊讶:甚至不能在一个整数上进行切换。Scala的匹配表达式要强大得多。哎呀,Cobol(19)85年的EVALUATE语句也更加有用。 - Jim Ferrans

1
答案取决于您正在做什么以及选择的分布情况。
如果一个条件占主导地位,那么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;
  }

话虽如此,如果性能不重要,那么选择你喜欢的任何一种方法作为最可读的(易于维护和编写)。

另一方面,如果您的代码处于性能重点区域,则应使用switch。

对于“非常大”的条件,Mario的lambdaj switcher示例非常酷,并且在初始化时小心处理将产生非常高的性能。它非常类似于优化器正在生成的编码。我会将“非常大”定义为选项数量足够大或复杂,值得输入所有内容,并且值得支持混淆以便后续开发人员浏览代码。(用注释解释为什么要这样做!)


1
首先,switch语句必须是可用的。如果switch基于变量的值,则可以使用它。如果它基于复杂的AND/OR/NOT布尔表达式,并且每个条件都有所不同,则根本无法使用它。
话虽如此,如果它适用,并且至少有2种情况,则我会使用switch。它更易于扩展,更易于阅读和检查。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接