Switch 块、Switch 表达式、Switch 模式匹配,越来越好用的 Switch

你好,我是看山。

本文收录在 《从小工到专家的 Java 进阶之旅》 系列专栏中。

与 if-else 一样,switch 语法是用来做条件判断的。当条件清晰简洁时,能够有效地提升代码可读性。switch 语法从 Java5 开始,Java12 增加了 Switch 表达式(Java14 提供正式版),Java17 增加 Switch 模式匹配(预览版)。

本文的目标是期望读者可以掌握 Switch 语法的所有能力,在需要的时候信手拈来。

if-else 与 switch 语法

我们先来个简单的例子看看 if-else 和 switch 语法的使用:

public static void demoOfIf(int num) {
    if (num == 0) {
        System.out.println("0");
    } else if (num == 1) {
        System.out.println("1");
    } else if (num == 2) {
        System.out.println("2");
    } else {
        System.out.println("3");
    }
}

public static void demoOfSwitch(int num) {
    switch (num) {
        case 0: {
            System.out.println("0");
            break;
        }
        case 1: {
            System.out.println("1");
            break;
        }
        case 2: {
            System.out.println("2");
            break;
        }
        default: {
            System.out.println("3");
        }
    }
}

上面的示例很简单,下面我们就来着重学习一下 Swith 语法。

Switch 块通用语法

switch(integral-selector) {
case value1: statement1; break;
case value2: statement2; break;
// ……
default: default-statement;
}

switch 语句是一种多路选择的简洁表达式,在 Java7 之前,switch 语句的表达式必须是整数值,这样会有很多的限制。于是在 Java7 中增加了 String 格式的支持,使应用场景更加丰富。

每个 case 执行语句末尾都有一个break关键字,它会让执行流程跳到 switch 的末尾。如果不加break,后面的 case 语句会继续执行,直到第一个break关键字。

比如:

public static void noBreak(int num) {
    switch (num) {
        case 0: {
            System.out.println("0");
        }
        case 1: {
            System.out.println("1");
        }
        case 2: {
            System.out.println("2");
            break;
        }
        default: {
            System.out.println("3");
        }
    }
}

执行noBreak(0)的结果会是:

0
1
2

基于这种特性,我们可以合并多个值的执行逻辑,比如下面这种写法:

public static void noBreak2(int num) {
    switch (num) {
        case 0:
        case 1:
        case 2: {
            System.out.println("0 or 1 or 2");
            break;
        }
        default: {
            System.out.println("3");
        }
    }
}

当参数是 0 或 1 或 2 时,结果相同,都是:

0 or 1 or 2

Switch 表达式

Switch 语句出现的姿势是条件判断、流程控制组件,与现在很流行的新语言对比,其写法显得非常笨拙,所以 Java 推出了 Switch 表达式语法,可以让我们写出更加简化的代码。这个扩展在 Java12 中作为预览版首次引入,需要在编译时增加-enable-preview开启,在 Java14 中正式提供,功能编号是 JEP 361

比如,我们通过 switch 语法简单计算工作日、休息日,在 Java12 之前需要这样写:

@Test
void testSwitch() {
    final DayOfWeek day = DayOfWeek.from(LocalDate.now());
    String typeOfDay = "";
    switch (day) {
        case MONDAY:
        case TUESDAY:
        case WEDNESDAY:
        case THURSDAY:
        case FRIDAY:
            typeOfDay = "Working Day";
            break;
        case SATURDAY:
        case SUNDAY:
            typeOfDay = "Rest Day";
            break;
    }

    Assertions.assertFalse(typeOfDay.isEmpty());
}

在 Java12 中的 Switch 表达式中,我们可以直接简化:

@Test
void testSwitchExpression() {
    final DayOfWeek day = DayOfWeek.SATURDAY;
    final String typeOfDay = switch (day) {
        case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Working Day";
        case SATURDAY, SUNDAY -> "Day Off";
    };

    Assertions.assertEquals("Day Off", typeOfDay);
}

是不是很清爽。不过,这里有一点不足的是,如果是需要执行一段业务逻辑,然后返回一个结果呢?于是 Java13 使用yield关键字补齐了这个功能:

@Test
void testSwitchExpression13() {
    final DayOfWeek day = DayOfWeek.SATURDAY;
    final String typeOfDay = switch (day) {
        case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> {
            System.out.println("Working Day: " + day);
            yield "Working Day";
        }
        case SATURDAY, SUNDAY -> {
            System.out.println("Day Off: " + day);
            yield "Day Off";
        }
    };

    Assertions.assertEquals("Day Off", typeOfDay);
}

Switch 模式匹配

到 Java17 时,又提供了 Switch 模式匹配功能。与 instanceof 模式匹配有些类似,是能够在 Switch 表达式实现类型自动转换。

比如:

static String formatterPatternSwitch(Object o) {
    return switch (o) {
        case null -> "null";
        case Integer i -> String.format("int %d", i);
        case Long l -> String.format("long %d", l);
        case Double d -> String.format("double %f", d);
        case String s -> String.format("String %s", s);
        default -> o.getClass().getSimpleName() + " " + o;
    };
}

public static void main(String[] args) {
    System.out.println(formatterPatternSwitch(null));
    System.out.println(formatterPatternSwitch("1"));
    System.out.println(formatterPatternSwitch(2));
    System.out.println(formatterPatternSwitch(3L));
    System.out.println(formatterPatternSwitch(4.0));
    System.out.println(formatterPatternSwitch(new AtomicLong(5)));
}

结果是:

null
String 1
int 2
long 3
double 4.000000
AtomicLong 5

可以看到,不只是类型自动转换,还可以直接判断是否是null,省了前置判断对象是否是null了。

青山不改,绿水长流,我们下次见。

推荐阅读


你好,我是看山。游于码界,戏享人生。如果文章对您有帮助,请点赞、收藏、关注。我还整理了一些精品学习资料,关注公众号「看山的小屋」,回复“资料”即可获得。

个人主页:https://www.howardliu.cn
个人博文:Switch 块、Switch 表达式、Switch 模式匹配,越来越好用的 Switch
CSDN 主页:https://kanshan.blog.csdn.net/
CSDN 博文:Switch 块、Switch 表达式、Switch 模式匹配,越来越好用的 Switch

👇🏻欢迎关注我的公众号「看山的小屋」,领取精选资料👇🏻

公众号:看山的小屋