为什么编译器在交换机中的每个代码块之后都不会自动放置break语句?这是出于历史原因吗?您何时需要执行多个代码块?
答案 0 :(得分:90)
有时,将多个案例与相同的代码块相关联会很有帮助,例如
case 'A':
case 'B':
case 'C':
doSomething();
break;
case 'D':
case 'E':
doSomethingElse();
break;
等。只是一个例子。
根据我的经验,通常情况下“糟透了”并且在一个案例中执行多个代码块是不好的风格,但在某些情况下可能会有用途。
答案 1 :(得分:29)
Historically,这是因为case
基本上定义了label
,也称为goto
来电的target point。 switch语句及其相关案例实际上只代表一个多路分支,在代码流中有多个潜在的入口点。
所有这一切,已经注意到几乎无限次break
几乎总是你在每个案例结束时都会有的默认行为。
答案 2 :(得分:27)
Java来自C,这是来自C的语法。
有时您希望多个case语句只有一个执行路径。 下面的示例将告诉您一个月内的天数。
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);
}
}
答案 3 :(得分:13)
你可以通过案例落实来做各种有趣的事情。
例如,假设您想要针对所有情况执行特定操作,但在某种情况下,您希望执行该操作以及其他操作。使用带有连接的switch语句会很容易。
switch (someValue)
{
case extendedActionValue:
// do extended action here, falls through to normal action
case normalActionValue:
case otherNormalActionValue:
// do normal action here
break;
}
当然,在案例结束时很容易忘记break
语句并导致意外行为。当你省略break语句时,好的编译器会警告你。
答案 4 :(得分:13)
我认为这是一个错误。作为一种语言结构,将break
作为默认值并使用fallthrough
关键字变得同样容易。我编写和阅读的大多数代码都会在每个案例后都有一段时间。
答案 5 :(得分:6)
为什么编译器不会在交换机中的每个代码块之后自动放置break语句?
不考虑良好的希望能够在几种情况下使用相同的块(可能是特殊的)...
是出于历史原因吗?您何时需要执行多个代码块?
它主要是为了与C兼容,可以说是goto
关键词在地球上漫游时的古代黑客攻击。 确实启用了一些令人惊奇的事情,当然,例如Duff's Device,但这是否有利于它还是反对的......充其量只是争论。
答案 6 :(得分:4)
因此,如果您需要多个案例来执行相同的操作,则不必重复代码:
case THIS:
case THAT:
{
code;
break;
}
或者你可以做以下事情:
case THIS:
{
do this;
}
case THAT:
{
do that;
}
以级联方式。
如果你问我,真的很容易出错/混淆。
答案 7 :(得分:3)
在切换break
之后使用case
来避免switch语句中的失败。尽管有趣的是,现在可以通过通过JEP-325实现的新形成的开关标签来实现。
通过这些更改,可以避免每次切换break
的{{1}},如进一步说明:-
case
在executing the above code with JDK-12上,比较输出可以看作是
public class SwitchExpressionsNoFallThrough {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int value = scanner.nextInt();
/*
* Before JEP-325
*/
switch (value) {
case 1:
System.out.println("one");
case 2:
System.out.println("two");
default:
System.out.println("many");
}
/*
* After JEP-325
*/
switch (value) {
case 1 ->System.out.println("one");
case 2 ->System.out.println("two");
default ->System.out.println("many");
}
}
}
和
//input
1
// output from the implementation before JEP-325
one
two
many
// output from the implementation after JEP-325
one
当然没有改变
//input
2
// output from the implementation before JEP-325
two
many
// output from the implementation after JEP-325
two
答案 8 :(得分:3)
就历史记录而言,Tony Hoare在20世纪60年代的“结构化编程”革命中发明了案例陈述。 Tony的case语句支持每个案例多个标签并自动退出,没有发出明显的break
语句。显式break
的要求来自BCPL / B / C线。 Dennis Ritchie写道(在ACM HOPL-II中):
例如,语言中不存在从BCPL switchon语句中转义的endcase 当我们在20世纪60年代学会它时,所以break关键字的重载要逃避 从B和C转换声明归因于不同的进化而不是有意识的变化。
我未能找到任何有关BCPL的历史着作,但Ritchie的评论表明break
或多或少是历史性事故。 BCPL后来解决了这个问题,但也许Ritchie和Thompson太忙于发明Unix而不愿意接受这样的细节: - )
答案 9 :(得分:3)
Java源自C,其遗产包括一种称为Duff's Device的技术。
这是一种优化,它依赖于在没有break;
语句的情况下控制从一个案例落到下一个案例的事实。在C标准化的时候,有很多代码就像“野外”一样,改变语言以打破这种结构会适得其反。
答案 10 :(得分:1)
正如人们之前所说的,它是允许堕落而不是错误,这是一个特征。
如果有太多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
正如所料。
答案 11 :(得分:0)
因为有些情况下你想要流过第一个块,例如为了避免在多个块中编写相同的代码,但仍然能够将它们分开以进行mroe控制。还有很多其他原因。
答案 12 :(得分:0)
这是一个老问题,但实际上我今天遇到了没有破坏声明的情况。当你需要按顺序组合不同的函数时,不使用break实际上非常有用。
e.g。使用http响应代码使用时间令牌验证用户
服务器响应代码401 - 令牌已过时 - >重新生成令牌和登录用户。
服务器响应代码200 - 令牌正常 - >登录用户。
在案例陈述中:
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响应调用登录用户函数,因为重新生成令牌时,运行时会跳转到案例200.
答案 13 :(得分:0)
您可以轻松地将其他类型的数字,月份,数量分开 如果在这种情况下,那就更好了;
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;
}
}
答案 14 :(得分:0)
我现在在我的switch语句中处理需要break
的项目,否则代码将无法正常工作。请耐心等待,我将为您提供一个很好的示例,说明您在switch语句中需要break
的原因。
想象一下,您有三种状态,一种等待用户输入数字,第二种用于计算数字,第三种用于打印总和。
在这种情况下,你有:
查看各州,您希望exaction的顺序从 state1 开始,然后是 state3 ,最后是 state2 。否则,我们只会打印用户输入而不计算总和。为了再次澄清它,我们等待用户输入一个值,然后计算总和并打印总和。
以下是一个示例代码:
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
,它将按此顺序执行, state1 , state2 和 state3 。但是使用break
,我们可以避免这种情况,并且可以在正确的过程中进行排序,该过程以state1开始,然后是state3,最后但最重要的是state2。
答案 15 :(得分:0)
编译器没有添加自动中断,可以通过从1和2中删除break语句来使用switch / case来测试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;
}
答案 16 :(得分:-1)
确实,因为有了一些聪明的位置,你可以级联执行块。