Java中的“switch”语句为什么要依赖于“break”关键字?

3
class switch1
{
    public static void main(String args[])
    {
        int a = 10;
        switch(a)
        {
            default: System.out.println("Default");
            case -1: System.out.println("-1");
        }
    }
}

我知道这个程序在匹配条件(在这种情况下是“default”后)没有指定break时会同时执行“默认”和“case -1”的语句。
但我不明白的是:
a)为什么在switch语句中需要使用break?
b)如果它只是匹配条件,为什么会执行无效匹配条件的语句(即执行“case -1”)?

4
这只是因为在C语言中是这样工作的,而Java与C相似到足以让程序员感到惊讶,如果它不这样做的话。 - Gabe
switch语句很可能是从GOTO语句演变而来的。如果你曾经使用过GOTO语句,你就可以想象为什么switch会表现出那种行为。 - aldrin
2
可能是为什么在case语句后面需要使用break?的重复问题。 - Raedwald
“switch” 在 C 语言中的定义方式是因为 C 本质上是汇编语言的一个宏语言,而对于机器指令来说,有一种特别优化的实现 C 中“switch”的方式。 - Marko Topolnik
9个回答

14

有时候您需要多个情况来执行同一个函数。例如,我让用户指定模式1或模式32来表示32位模式,以及模式2或模式64来表示64位模式。

switch (input) {

    case 1:
    case 32:
        /* Do 32-bit related code */
        break;
    case 2:
    case 64:
        /* Do 64-bit related code */
        break;
    default:
        System.out.println("Invalid input");

}
这就是为什么"breaks"很重要。它们告诉"switch"语句在给定情况下何时停止执行代码。此外,"default"通常用于当"switch"不匹配任何情况时。

2
@abmitchell +1。看起来这是真正的代码 :) - Jayan
此外,您需要将默认情况放在底部,否则它将始终被执行。- 这不是完全正确的。 - Paul Bellora
你是正确的,但由于 switch 按顺序移动到各个 case(即先是 2,然后是 64),因此在顶部设置默认值可能会令人困惑。不过我已经将该注释删除了。 - hotforfeature
它不一定按顺序遍历各个情况。你可能在想if语句。 - Cody Gray

4
没有使用break语句的switch语句会让你做出如下操作:
// Compute the most significant bit set in a number from 0 to 7
int topBit = -1;
switch(n) {
case 0:
    topBit = 0;
    break;
case 1:
    topBit = 1;
    break;
case 2:
case 3:
    topBit = 2;
    break;
case 4:
case 5:
case 6:
case 7:
    topBit = 3;
    break;
}

本质上,它允许您创建一组标签,并在顶部设置条件以让您跳转到初始标签。之后,执行将继续直到出现break或达到switch的结尾。这种技术很古老 - 它从汇编时代就存在了,并且通过被包含在C中而进入了Java和其他几种语言。


1
“标签集” - 这是一个重要的提示。case语句不是条件,而是标签。 - aldrin

1

1

a) 为什么switch语句需要依赖break语句来实现其目的?

因为这是它们定义的方式。它是从C语言复制过来的。Pascal没有fall-through,所以也没有break。它还有case范围,而Java则不具备这一点。语言允许不同。或者相同。

b) 为什么它甚至执行无效匹配条件的语句(即执行“case -1”)?

因为这是它们定义的方式,如果你没有放置一个break,那么就会发生fall-through。

如果它只是做匹配,那为什么会执行无效匹配条件的语句?

我不理解这个问题。它并不是做匹配。它执行一个索引跳转到相关的case,并在你没有放置一个break的情况下继续执行下一个语句。


1

关于a,需要使用break的原因是可以使用简写符号,在底部块中放置常见代码。在某些情况下,这可能会使代码更易读。

有关fallthrough的更多信息,请参见“C#中的switch语句fallthrough?”。

关于b,由于它匹配了default情况,该行将被执行。由于该块中没有break,因此无论是否匹配,下一行也将被执行。

尝试

switch (a)
{
    case 10: System.out.println("This is 10.");
    case 9 : System.out.println("This is 9.");
             break;
    case 8 : System.out.println("This is 8.");
             break;
    default: System.out.println("Default");
}

由于匹配的case没有break,所以输出结果为:
This is 10.
This is 9.

将这与将a设置为11、9或8进行比较。


1

以下是关于Java语言规范中break语句的部分

break语句可使程序跳出包含它的语句。

以及...

break语句总是会突然终止执行。

a) 它只允许将控制权转移出该case语句。

b) 它执行不符合预期匹配条件的原因是,有特定条件下连续的case语句被认为是有效的(摘自Java教程):

List<String> futureMonths = new ArrayList<String>();
int month = 8;
switch (month) {
    case 1:  futureMonths.add("January");
    case 2:  futureMonths.add("February");
    case 3:  futureMonths.add("March");
    case 4:  futureMonths.add("April");
    case 5:  futureMonths.add("May");
    case 6:  futureMonths.add("June");
    case 7:  futureMonths.add("July");
    case 8:  futureMonths.add("August");
    case 9:  futureMonths.add("September");
    case 10: futureMonths.add("October");
    case 11: futureMonths.add("November");
    case 12: futureMonths.add("December");
             break;
    default: break;
}

for (String monthName : futureMonths) {
    System.out.println(monthName);
}

这将输出:

八月

九月

十月

十一月

十二月


0
如果您在循环中添加了break,它将会退出该循环。对于switch语句来说,它会进入正确的case并执行代码,直到break出现并退出switch语句。如果您删除了break,它将会继续执行下一个case,直到遇到break为止。如果没有break;,代码将会崩溃。
所以基本上它可以分离不同的情况。

0

a) 为什么在 switch 中需要 fall-through / required break?

fall-through 行为在某些情况下非常有用,但问题在于它在普通情况下是额外的工作。因此,合理地期望“break”关键字在更现代的语言中不是必需的。

那么为什么还存在呢?为了匹配 C++ 的行为(Java 设计时占主导地位的语言),再次匹配 C 的行为(C++ 设计时占主导地位的语言)。至于 C,它(以及其前身 B 和 BCPL)通常看起来是这样的,以使构建高效编译器更容易。基本上,switch 语句的工作方式是在汇编语言中实现它的自然方式。

b) 它的行为方式从使用 fall-through 的决定中逻辑上得出。


0

在 Switch case 中,重点是 break 语句。

每个 break 语句都会终止包含它的 switch 语句。控制流程将继续执行 switch 块后面的第一条语句。这些 break 语句是必需的,因为如果没有它们,switch 块中的语句将会穿透:匹配的 case 标签后面的所有语句都会按顺序执行,而不管后续 case 标签的表达式如何,直到遇到 break 语句为止。

程序 SwitchDemoFallThrough 显示了在 switch 块中穿透的语句。该程序显示与整数月份对应的月份以及接下来的月份:

public class SwitchDemoFallThrough {

public static void main(String[] args) {
    java.util.ArrayList<String> futureMonths =
        new java.util.ArrayList<String>();

    int month = 8;

    switch (month) {
        case 1:  futureMonths.add("January");
        case 2:  futureMonths.add("February");
        case 3:  futureMonths.add("March");
        case 4:  futureMonths.add("April");
        case 5:  futureMonths.add("May");
        case 6:  futureMonths.add("June");
        case 7:  futureMonths.add("July");
        case 8:  futureMonths.add("August");
        case 9:  futureMonths.add("September");
        case 10: futureMonths.add("October");
        case 11: futureMonths.add("November");
        case 12: futureMonths.add("December");
                 break;
        default: break;
    }

    if (futureMonths.isEmpty()) {
        System.out.println("Invalid month number");
    } else {
        for (String monthName : futureMonths) {
           System.out.println(monthName);
        }
    }
}

}

以下是代码的输出:

八月 九月 十月 十一月 十二月

从技术上讲,最后一个break语句并不是必需的,因为程序会自动跳出switch语句。但建议使用break语句,这样修改代码时更容易、更不容易出错。default部分处理所有未被case部分显式处理的值。

请点击此处查看switch的完整信息。


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