为什么我们需要打破案件陈述?

为什么编译器不会在交换机中的每个代码块之后自动放置break语句? 是因为历史原因吗? 你什么时候需要多个代码块来执行?

有时,有多个与相同代码块关联的案例会很有帮助,例如

case 'A': case 'B': case 'C': doSomething(); break; case 'D': case 'E': doSomethingElse(); break; 

只是一个例子。

根据我的经验,通常情况下,“跌倒”是一种不好的风格,并且在一种情况下会执行多个代码块,但在某些情况下可能会有用处。

从历史上看 ,这是因为case本质上是定义了一个label ,也就是所谓的“ goto的目标点 。 switch语句及其相关案例实际上只是代表一个多路分支,其中有多个潜在的入口点进入代码stream。

所有这些都说明了,几乎所有的情况下都会有这样的情况发生,即break几乎总是你想要的默认行为。

Java来自C,这是从C语法

有时候你想要多个case语句只有一个执行path。 下面是一个例子,它会告诉你一个月中有多less天。

 class SwitchDemo2 { public static void main(String[] args) { int month = 2; int year = 2000; int numDays = 0; switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: numDays = 31; break; case 4: case 6: case 9: case 11: numDays = 30; break; case 2: if ( ((year % 4 == 0) && !(year % 100 == 0)) || (year % 400 == 0) ) numDays = 29; else numDays = 28; break; default: System.out.println("Invalid month."); break; } System.out.println("Number of Days = " + numDays); } } 

你可以做一切有趣的事情,案件通过。

例如,假设你想对所有情况做一个特定的动作,但是在某种情况下,你想要做这个动作加上其他的东西。 使用switch-statement和fall-through会使它变得非常容易。

 switch (someValue) { case extendedActionValue: // do extended action here, falls through to normal action case normalActionValue: case otherNormalActionValue: // do normal action here break; } 

当然,在案件结束时很容易忘记break语句,并导致意外的行为。 好的编译器会在你忽略break语句时提醒你。

我认为这是一个错误。 作为一种语言结构,它与默认一样简单,而是有一个fallthrough关键字。 大部分我已经写和读的代码在每个案例之后都有一个中断。

为什么编译器不会在交换机中的每个代码块之后自动放置break语句?

撇开好的愿望,能够使用相同的块在几个情况下(这可能是特殊的)…

是因为历史原因吗? 你什么时候需要多个代码块来执行?

这主要是为了与C兼容,而且可以说是一个来自古代的时代,当关键字漫游到地球的时候。 它确实使一些令人惊讶的事情,当然,如达夫的设备 ,但是这是一个有利或反对的点是…充其量是辩论。

所以如果你需要几个例子来做同样的事情,你不必重复代码:

 case THIS: case THAT: { code; break; } 

或者你可以做这样的事情:

 case THIS: { do this; } case THAT: { do that; } 

以级联的方式。

如果你问我,真的很容易出错/混乱。

Java源自C,其传统包括一种称为Duff's Device的技术。 这是一个优化,它依赖于控制从一个案件到另一个案件的情况下,在没有break;的情况下break; 声明。 在C被标准化的时候,有很多这样的“野外”代码,改变语言来打破这种结构会起反作用。

就历史logging而言,托尼·霍尔(Tony Hoare)在20世纪60年代的“结构化编程”革命期间发明了这个案例陈述。 Tony的案例陈述支持每个案例的多个标签,并且自动退出,而且不会有破烂的断言。 BCPL / B / C系列产品是明确的break要求。 丹尼斯·里奇(ACM HOPL-II)写道:

例如,当我们在二十世纪六十年代学到这个语言时,从BCPL switchon语句中逃逸出来的endcase并没有出现在这个语言中,所以break关键字的重载从B和C switch语句中逃逸的原因归结于发散的进化而不是有意识的更改。

我还没有find任何关于BCPL的历史着作,但是Ritchie的评论表明,这个break或多或less是历史的事故。 BCPL后来解决了这个问题,但是也许Ritchie和Thompson忙于发明Unix,以致于无法忍受这样的细节:-)

没有通过编译器添加自动中断,可以使用开关/shell通过从1和2中删除break语句来testing条件,如1 <= a <= 3

 switch(a) { case 1: //I'm between 1 and 3 case 2: //I'm between 1 and 3 case 3: //I'm between 1 and 3 break; } 

因为在某些情况下,您想要通过第一个块来避免在多个块中编写相同的代码,但仍然可以将它们划分为mroe控件。 还有很多其他的原因。

这是一个古老的问题,但实际上我今天碰到了使用这个案件没有断言。 当你需要按顺序组合不同的function时,不使用中断是非常有用的。

例如使用http响应代码用时间令牌来authentication用户

服务器响应代码401 – 令牌已过期 – >重新生成令牌并将用户login。
服务器响应代码200 – 令牌可以 – >将用户login。

在情况下陈述:

 case 404: case 500: { Log.v("Server responses","Unable to respond due to server error"); break; } case 401: { //regenerate token } case 200: { // log in user break; } 

使用它你不需要为401响应调用login用户函数,因为当令牌被重新生成时,运行时跳转到情况200。

您可以轻松地分隔其他types的数字,月份,数量。
如果在这种情况下,这是更好的;

 public static void spanishNumbers(String span){ span = span.toLowerCase().replace(" ", ""); switch (span){ case "1": case "jan": System.out.println("uno"); break; case "2": case "feb": System.out.println("dos"); break; case "3": case "mar": System.out.println("tres"); break; case "4": case "apr": System.out.println("cuatro"); break; case "5": case "may": System.out.println("cinco"); break; case "6": case "jun": System.out.println("seis"); break; case "7": case "jul": System.out.println("seite"); break; case "8": case "aug": System.out.println("ocho"); break; case "9": case "sep": System.out.println("nueve"); break; case "10": case "oct": System.out.println("diez"); break; } } 

我现在在开发语句中需要break项目,否则代码将无法工作。 和我一起,我会给你一个很好的例子,说明为什么你需要在你的switch语句中break

想象一下,你有三个状态,一个等待用户input一个数字,第二个计算它,第三个打印总和。

在这种情况下你有:

  1. 状态1 – 等待用户input一个号码
  2. 状态2 – 打印总和
  3. state3 – 计算总和

看看这些状态,你会希望exaction的顺序从state1开始,然后是state3 ,最后是state2 。 否则,我们将只打印用户input,而不计算总和。 只是为了澄清一下,我们等待用户input一个值,然后计算总和并打印总和。

这是一个示例代码:

 while(1){ switch(state){ case state1: // Wait for user input code state = state3; // Jump to state3 break; case state2: //Print the sum code state = state3; // Jump to state3; case state3: // Calculate the sum code state = wait; // Jump to state1 break; } } 

如果我们不使用break ,它将按照state1state2state3的顺序执行。 但是使用break ,我们可以避免这种情况,并且可以在以state1,state3和last2开始的正确的过程中进行sorting。

正如人们之前所说的那样,这是允许通过的,这不是一个错误,而是一个特征。 如果太多的break语句让你厌烦,你可以通过使用return语句来轻松的摆脱它们。 这实际上是一个好的做法,因为你的方法应该尽可能小(为了可读性和可维护性),所以switch语句对于一个方法已经足够大了,因此,一个好的方法不应该包含任何其他的东西,这个就是一个例子:

 public class SwitchTester{ private static final Log log = LogFactory.getLog(SwitchTester.class); public static void main(String[] args){ log.info(monthsOfTheSeason(Season.WINTER)); log.info(monthsOfTheSeason(Season.SPRING)); log.info(monthsOfTheSeason(Season.SUMMER)); log.info(monthsOfTheSeason(Season.AUTUMN)); } enum Season{WINTER, SPRING, SUMMER, AUTUMN}; static String monthsOfTheSeason(Season season){ switch(season){ case WINTER: return "Dec, Jan, Feb"; case SPRING: return "Mar, Apr, May"; case SUMMER: return "Jun, Jul, Aug"; case AUTUMN: return "Sep, Oct, Nov"; default: //actually a NullPointerException will be thrown before reaching this throw new IllegalArgumentException("Season must not be null"); } } } 

执行打印:

 12:37:25.760 [main] INFO lang.SwitchTester - Dec, Jan, Feb 12:37:25.762 [main] INFO lang.SwitchTester - Mar, Apr, May 12:37:25.762 [main] INFO lang.SwitchTester - Jun, Jul, Aug 12:37:25.762 [main] INFO lang.SwitchTester - Sep, Oct, Nov 

如预期。

确切地说,因为有了一些巧妙的放置,您可以级联执行块。