Switch 语句

使用Switch语句控制程序流程

switch 语句是Java语言中五种控制流语句之一,它允许存在任意数量的执行路径。switch语句以选择器变量作为参数,并根据该变量的值来选择将要执行的路径。

您必须从以下类型中选择选择器变量的类型:

  • byte, short, char, int 基础类型
  • Character, Byte, Short, Integer 包装类型
  • 枚举类型
  • 字符串类型

值得注意的是,以下基本类型不能用于选择器变量的类型:boolean、long、floatdouble

让我们看一个使用switch语句的简单示例:

int quarter = 1; // any value
    String quarterLabel = null ;
    switch (quarter) {
        case 0: quarterLabel = "Q1 - Winter";`
            break;
        case 1: quarterLabel = "Q2 - Spring";
            break;
        case 2: quarterLabel = "Q3 - Summer";
            break;
        case 3: quarterLabel = "Q4 - Fall";
            break;
        default: quarterLabel = "Unknown quarter";        
    }

switch 语句的主体称为 switch 代码块。switch 代码块中的语句可标记为一个或多个 case 标签或 default 标签。switch 语句会先评估其表达式,然后执行所有位于匹配 case 标签之后的语句。

您可能已经注意到 break 关键字的使用。每个 break 语句都会终止其所在的 switch 语句块。控制流将从 switch 块后的第一个语句继续执行。break 语句是必要的,因为若没有它们,switch 块中的语句会发生穿透执行。匹配的 case 标签之后的所有语句都会依次执行,无论后续case 标签的表达式如何,直到遇到 break 语句为止。

以下代码使用穿透机制填充 futureMonths 列表。

public static void main(String[] args) {
    int month = 8;
    List<String> futureMonths = new ArrayList<>();
    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;
    }
    IO.println(futureMonths);
}

程序将输出以下内容:

[August, September, October, November, December]

严格来说,最后的 break 语句并非必需,因为流程会自然跳出 switch 语句。但建议使用 break 语句,这样修改代码时更容易且不易出错。

default 部分处理所有未被任何 case 部分明确处理的值。
以下代码示例展示了单个语句如何包含多个 case 标签。该示例计算特定月份的天数:

public int calculateDaysInMonth(int year, int month){
    int days = 0;
    switch(month){
        case 1, 3, 5, 7, 8, 10, 12 -> days = 31;
        case 4, 6, 9, 11 -> days = 30;
        case 2 ->  {
            if(((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)){
                days = 29;
            } else {
                days = 28;
            }
        }
        default -> IO.println("Invalid month: " + month);
    }
    return days;
}

这段代码中一个语句对应多个情况。

在 Switch 语句和 If-then-else 语句之间进行选择

决定使用 if-then-else 语句还是 switch 语句,取决于代码的可读性以及语句所测试的表达式类型。if-then-else 语句可基于值的范围或条件来测试表达式,而 switch 语句仅能基于单个整数、枚举值或字符串对象来测试表达式。例如,以下代码可以用 switch 语句来实现。

int month = ...; // any month
if (month ==1) {
    IO.println("January");
} else if (month == 2){
    IO.println("February");
} ... // and so on

另一方面,以下内容无法使用 switch 语句编写,因为 switch 语句不支持布尔类型的标签。

int remperature = ...; // any temperature
if (temperature < 0) {
    IO.println("Water is ice");
} else if (temperature < 100){
    IO.println("Water is liquid, known as water");
} else {
    IO.println("Water is vapor");
}

使用 String 作为 Case 标签

在 Java SE 7 及更高版本中,您可以在 switch 语句的表达式中使用 String 对象。以下代码示例根据名为 month 的 String 值显示月份编号。

String month = "March"; // any month
int monthNumber = -1;
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;
}

switch 表达式中,字符串与每个 case 标签关联的表达式进行比较,如同使用 String.equals() 方法一样。为了使本示例能够接受任何月份(不区分大小写),month 被转换为小写(使用 toLowerCase() 方法),且所有与 case 标签关联的字符串均为小写。

Null 值处理

switch 语句的选项变量可以是对象,因此该对象可能为空。你应保护代码免受空选项变量的影响,因为此时switch语句将抛出 NullPointerException 异常。