ZetCode

Java switch 表达式

最后修改于 2025 年 5 月 31 日

在本文中,我们将展示如何在 Java 中使用 switch 表达式。

Switch 表达式提供了一种更简洁、更易读的方式来编写多路分支逻辑。 它们是对经典 switch 语句的强大增强。

与传统的 switch 语句不同,switch 表达式可以返回值。

Java switch 表达式支持使用多个 case 标签。 这些也称为分支。 每个 case 标签后跟 -> 箭头语法。

switch 表达式必须是穷尽的。 除了少数情况(例如枚举,编译器可以确定所有可能的选项)外,我们必须使用 default 分支。 当没有其他选项匹配时,它将被执行。

Main.java
void main() {

    System.out.print("Enter a domain: ");

    try (var sc = new Scanner(System.in)) {

        String domain = sc.nextLine();
        domain = domain.trim().toLowerCase();

        switch (domain) {

            case "us" -> System.out.println("United States");
            case "de" -> System.out.println("Germany");
            case "sk" -> System.out.println("Slovakia");
            case "hu" -> System.out.println("Hungary");
            default -> System.out.println("Unknown");
        }
    }
}

要求用户输入域名。 域名被读取并存储在一个变量中。 该变量使用 switch 关键字针对选项列表进行测试。 在我们的程序中,我们有一个域名变量。 我们从命令行读取该变量的值。

case "us" -> System.out.println("United States");

我们使用 case 语句来测试变量的值。 有几个选项。 例如,如果该值等于“us”,则将“United States”字符串打印到控制台。 一旦选项匹配,就不会评估其他分支。

default -> System.out.println("Unknown");

当该值与任何先前的分支不匹配时,将执行 default 分支。

使用枚举

在下一个示例中,我们将使用枚举。

Main.java
void main() {

    Season season = Season.randomSeason();

    String msg = switch (season) {

        case Season.SPRING -> "Spring";
        case Season.SUMMER -> "Summer";
        case Season.AUTUMN -> "Autumn";
        case Season.WINTER -> "Winter";
    };

    System.out.println(msg);
}

enum Season {
    SPRING,
    SUMMER,
    AUTUMN,
    WINTER;

    public static Season randomSeason() {
        
        var random = new Random();
        int ridx = random.nextInt(Season.values().length);
        return Season.values()[ridx];
    }
}

我们定义一个 Season 枚举。 该枚举包含一个 randomSeason 方法,该方法随机创建一个 Season 值。 根据选择的值,我们打印一条消息。

var msg = switch (season) {

    case Season.Spring -> "Spring";
    case Season.Summer -> "Summer";
    case Season.Autumn -> "Autumn";
    case Season.Winter -> "Winter";
};

System.out.println(msg);

我们根据 switch 表达式检查该值。 该表达式返回枚举的字符串表示形式。 请注意,switch 表达式是穷尽的。

检查多个选项

我们可以在一个分支中检查多个选项。

Main.java
void main() {

    Grade grade = Grade.randomGrade();

    String msg = switch (grade) {

        case Grade.A, Grade.B, Grade.C, Grade.D, Grade.E, Grade.F -> "passsed";
        case Grade.FX -> "failed";
    };

    System.out.printf("%s - %s", grade - msg");
}

enum Grade {
    A, B, C, D, E, F, FX;

    public static Grade randomGrade() {

        var random = new Random();
        int rdx = random.nextInt(Grade.values().length);
        return Grade.values()[rdx];
    }
}

我们有一个成绩列表。对于 A 到 F 的成绩,我们通过了示例。对于 FX 成绩,我们考试不及格。

String msg = switch (grade) {

    case Grade.A, Grade.B, Grade.C, Grade.D, Grade.E, Grade.F -> "passsed";
    case Grade.FX -> "failed";
};

我们在第一个分支中检查六个选项。 它们用逗号分隔。

检查类型

在以下程序中,我们检查值的类型。

Main.java
void main() {

    List<Object> objects = List.of("falcon", new BigDecimal(120001212),
            new int[] { 1, 2, 3, 4, 5 }, new String[] { "sky", "blue", "rock" });

    objects.forEach(e -> System.out.println(checkType(e)));
}

String checkType(Object o) {

    return switch (o) {

        case String str -> "String";
        case BigDecimal bd -> "BigDecimal";
        case Integer i -> "Integer";
        case int[] ai -> "Array of integers";
        case String[] as -> "Array of strings";
        default -> "n/a";
    };
}

我们有一个包含各种类型的对象的列表。 使用 switch 表达式,我们确定每个值的类型。

return switch (o) {

    case String str -> "String";
    case BigDecimal bd -> "BigDecimal";
    case Integer i -> "Integer";
    case int[] ai -> "Array of integers";
    case String[] as -> "Array of strings";
    default -> "n/a";
};

在 case 关键字之后,我们提供类型。 如果类型匹配,则执行该分支并返回相应的字符串。

When 守卫

When 守卫可用于在选项上应用简单的表达式。 可以将表达式与 &&|| 运算符组合使用。

Main.java
void main() {

    int[] ages = { 12, 23, 45, 0, 67, 88, 43, 55, -4};

    Arrays.stream(ages).forEach(e -> System.out.printf("%s - %s%n", e, checkAge(e)));
}

String checkAge(Integer age) {

    return switch (age) {

        case Integer i when i < 18 && i > 0-> "minor";
        case Integer i when i >= 18 && i < 64 -> "adult";
        case Integer i when i > 64 -> "senior";
        default -> "n/a";
    };
}

我们有一个表示年龄的整数数组。 我们使用 switch 表达式将这些值映射到年龄类别。

return switch (age) {

    case Integer i when i < 18 && i > 0-> "minor";
    case Integer i when i >= 18 && i < 64 -> "adult";
    case Integer i when i > 64 -> "senior";
    default -> "n/a";
};

when 关键字之后,我们使用 < 18 && i > 0-> 表达式来检查该数字是否在 0 到 18 之间。

Null 值

可以在 switch 表达式中检查 null 值。

Main.java
void main() {

    List<Integer> data = new ArrayList<>();

    data.add(2);
    data.add(5);
    data.add(0);
    data.add(null);
    data.add(-4);
    data.add(6);

    data.forEach(e -> System.out.printf("%s - %s%n", e, checkValue(e)));
}

String checkValue(Integer i) {

    return switch (i) {
        case null -> "null value";
        case 0 -> "zero value";
        case Integer n when n > 0 -> "positive value";
        case Integer n when n < 0 -> "negative value";
        default -> "n/a";
    };
};

我们有一个整数列表;还有一个 null 值。

case null -> "null value";

此分支检查该值是否为 null。

记录字段

可以在 when 守卫中检查记录字段。

Main.java
void main() {

    var points = List.of(Point.of(0, 0), Point.of(-3, -3), Point.of(-3, -3),
            Point.of(12, -1));

    points.forEach(p -> System.out.printf("%s - %s%n", p, checkQuadrant(p)));
}

String checkQuadrant(Point p) {

    return switch (p) {

        case Point(var x, var y) when x == 0 && y == 0 -> "origin";
        case Point(var x, var y) when x > 0 && y > 0 -> "Q I";
        case Point(var x, var y) when x < 0 && y > 0 -> "Q II";
        case Point(var x, var y) when x < 0 && y < 0 -> "Q III";
        case Point(var x, var y) when x > 0 && y < 0 -> "Q IV";
        default -> "n/a";
    };
};

record Point(int x, int y) {
    static Point of(int x, int y) {
        return new Point(x, y);
    }
}

我们有一个坐标系中的点列表。 我们将每个点映射到其对应的象限。

return switch (p) {

    case Point(var x, var y) when x == 0 && y == 0 -> "origin";
    case Point(var x, var y) when x > 0 && y > 0 -> "Q I";
    case Point(var x, var y) when x < 0 && y > 0 -> "Q II";
    case Point(var x, var y) when x < 0 && y < 0 -> "Q III";
    case Point(var x, var y) when x > 0 && y < 0 -> "Q IV";
    default -> "n/a";
};

记录遵循 case 关键字。 在 when 守卫之后,我们可以直接在表达式中使用这些字段。

使用 Switch 表达式实现 FizzBuzz

你可以使用带有 when 守卫的 switch 表达式,以简洁且具有表现力的方式实现经典的 FizzBuzz 问题。 这种方法利用模式匹配和守卫来干净利落地处理多个条件。

Main.java
void main() {

    IntStream.range(1, 101).forEach(this::doFizzBuzz);
}

void doFizzBuzz(int e) {

    switch (e) {

        case int n when n % 3 == 0 && n % 5 == 0 -> System.out.println("FizzBuzz");
        case int n when n % 3 == 0 -> System.out.println("Fizz");
        case int n when n % 5 == 0 -> System.out.println("Buzz");
        default -> System.out.println(e);
    }
}

在此示例中,doFizzBuzz 方法使用带有 when 守卫的 switch 表达式,对可被 3 整除的数字打印 "Fizz",对可被 5 整除的数字打印 "Buzz",对既可被 3 整除又可被 5 整除的数字打印 "FizzBuzz"。 所有其他数字都按原样打印。 这演示了 switch 表达式如何简化复杂的条件逻辑。

来源

Java 语言 - 参考

在本文中,我们讨论了 Java 中的 switch 表达式。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有Java教程