# `switch`语句

> 原文： [https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html)

与`if-then`和`if-then-else`语句不同，`switch`语句可以有许多可能的执行路径。 `switch`与`byte`，`short`，`char`和`int`原始数据类型一起使用。它也适用于 _ 枚举类型 _（在[枚举类型](../javaOO/enum.html)中讨论）， [`String`](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) 类，以及一些包含某些原始类型的特殊类： [`Character`](https://docs.oracle.com/javase/8/docs/api/java/lang/Character.html) ， [`Byte`](https://docs.oracle.com/javase/8/docs/api/java/lang/Byte.html) ， [`Short`](https://docs.oracle.com/javase/8/docs/api/java/lang/Short.html) 和 [`Integer`](https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html) （在[数字和字符串](../data/index.html)中讨论] ）。

以下代码示例 [`SwitchDemo`](examples/SwitchDemo.java) 声明名为`month`的`int`，其值代表一个月。代码使用`switch`语句根据`month`的值显示月份名称。

```
public class SwitchDemo {
    public static void main(String[] args) {

        int month = 8;
        String monthString;
        switch (month) {
            case 1:  monthString = "January";
                     break;
            case 2:  monthString = "February";
                     break;
            case 3:  monthString = "March";
                     break;
            case 4:  monthString = "April";
                     break;
            case 5:  monthString = "May";
                     break;
            case 6:  monthString = "June";
                     break;
            case 7:  monthString = "July";
                     break;
            case 8:  monthString = "August";
                     break;
            case 9:  monthString = "September";
                     break;
            case 10: monthString = "October";
                     break;
            case 11: monthString = "November";
                     break;
            case 12: monthString = "December";
                     break;
            default: monthString = "Invalid month";
                     break;
        }
        System.out.println(monthString);
    }
}

```

在这种情况下，`August`打印到标准输出。

`switch`语句的主体称为 _ 开关块 _。 `switch`块中的语句可以用一个或多个`case`或`default`标签标记。 `switch`语句计算其表达式，然后执行匹配`case`标签后面的所有语句。

您还可以使用`if-then-else`语句显示月份的名称：

```
int month = 8;
if (month == 1) {
    System.out.println("January");
} else if (month == 2) {
    System.out.println("February");
}
...  // and so on

```

决定是否使用`if-then-else`语句或`switch`语句是基于可读性和语句正在测试的表达式。 `if-then-else`语句可以基于值或条件的范围来测试表达式，而`switch`语句仅基于单个整数，枚举值或`String`对象来测试表达式。

另一个兴趣点是`break`声明。每个`break`语句终止封闭的`switch`语句。控制流继续`switch`块之后的第一个语句。 `break`语句是必要的，因为没有它们，`switch`块 _ 中的语句将通过 _ 落下：匹配的`case`标签之后的所有语句将按顺序执行，而不管后续`case`标签的表达如何，直到遇到`break`语句。程序 [`SwitchDemoFallThrough`](examples/SwitchDemoFallThrough.java) 显示`switch`程序段中的语句。程序显示对应于整数`month`的月份以及该年份中的月份：

```
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);
            }
        }
    }
}

```

这是代码的输出：

```
August
September
October
November
December

```

从技术上讲，最终的`break`不是必需的，因为流量超出了`switch`声明。建议使用`break`，以便更容易修改代码并减少错误。 `default`部分处理未由`case`部分之一显式处理的所有值。

以下代码示例 [`SwitchDemo2`](examples/SwitchDemo2.java) 显示了语句如何具有多个`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);
    }
}

```

这是代码的输出：

```
Number of Days = 29

```

## 在交换机语句中使用字符串

在 Java SE 7 及更高版本中，您可以在`switch`语句的表达式中使用`String`对象。以下代码示例 [`StringSwitchDemo`](examples/StringSwitchDemo.java) 根据名为`month`的`String`的值显示月份编号：

```
public class StringSwitchDemo {

    public static int getMonthNumber(String month) {

        int monthNumber = 0;

        if (month == null) {
            return monthNumber;
        }

        switch (month.toLowerCase()) {
            case "january":
                monthNumber = 1;
                break;
            case "february":
                monthNumber = 2;
                break;
            case "march":
                monthNumber = 3;
                break;
            case "april":
                monthNumber = 4;
                break;
            case "may":
                monthNumber = 5;
                break;
            case "june":
                monthNumber = 6;
                break;
            case "july":
                monthNumber = 7;
                break;
            case "august":
                monthNumber = 8;
                break;
            case "september":
                monthNumber = 9;
                break;
            case "october":
                monthNumber = 10;
                break;
            case "november":
                monthNumber = 11;
                break;
            case "december":
                monthNumber = 12;
                break;
            default: 
                monthNumber = 0;
                break;
        }

        return monthNumber;
    }

    public static void main(String[] args) {

        String month = "August";

        int returnedMonthNumber =
            StringSwitchDemo.getMonthNumber(month);

        if (returnedMonthNumber == 0) {
            System.out.println("Invalid month");
        } else {
            System.out.println(returnedMonthNumber);
        }
    }
}

```

此代码的输出为`8`。

将`switch`表达式中的`String`与每个`case`标记相关的表达式进行比较，就好像正在使用 [`String.equals`](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#equals-java.lang.Object-) 方法一样。为了使`StringSwitchDemo`示例无论何种情况都接受任何月份，`month`将转换为小写（使用 [`toLowerCase`](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#toLowerCase--) 方法），并且与`case`标签关联的所有字符串都是小写的。

**注**：此示例检查`switch`语句中的表达式是否为`null`。确保任何`switch`语句中的表达式不为 null，以防止抛出`NullPointerException`。