你能用逗号连接 switch 语句的两种情况吗

Can you connect two cases of a switch statement using a comma

我在最近的项目中一直在使用 switch 语句,并希望有两个可能的值执行相同的代码。所以我查找了如何做到这一点的方法。我找到的唯一答案是这样的:

switch (element) {
   case hi:
   case hello:
      //do something here
      break;
}

但我做了更多的实验,发现我的 IDE 并没有抱怨:

switch (element) {
   case hi, hello:
      //do something here
      break;
}

所以我尝试了一下,发现它有效。所以我想知道使用这种方法是否有问题,因为我在网上没有找到任何东西。我只是希望能够使用它,因为它看起来干净多了。

这在 Java 中不可用,但是您可以使用 Kotlin 来做这件事,它与 Java

100% 兼容

您的原始代码段使用 fall-through 对两种情况给出相同的响应;有些人觉得这很难阅读和理解。 Java 12 为我们提供了两个相关功能,人们发现这些功能有助于清理他们的 switch 语句,其中之一是您在此处发现的:

  1. case 可以用逗号分隔而不是依赖 fall-through
  2. 可以使用箭头标签代替冒号和换行符;命令。

因此,如果你发现自己不喜欢fall-through,又不想担心自己是否记住了break命令,你可以这样写开关:

switch (element) {
    case hi, hello -> // do something here
    case goodbye, bye -> // do something else here
}

请注意,在这种情况下,我们没有任何 break 语句,但是在 hi case 和 bye case 之间没有失败;由于箭头标签,它们是分开的。

java(12 及更高版本)的最新版本在 switch 上投入了大量工作。现在有很多形式。其中一些形式有一个基本原则,强烈表明一些新的语法特征很重要,为了保持一致性,如果其他形式也可以允许该特征,其他形式也会更新。

历史

最初的 java 1.0 开关是 C 的直接副本(这解释了它们完全奇怪和愚蠢的语法;这是 C 所拥有的,并且 java 被设计为 comfortable 给 C 程序员。我们可以抱怨这意味着语法是愚蠢的,但很难否认 C 风格的语法,无论它看起来多么疯狂,已经接管了这个星球,C、C#、Java 和 Java 脚本加在一起占据了很大一部分 'market' 可以这么说)。

它:

  • 要求您切换的东西在 int 上并且仅在 int
  • 每个案例都是一个特定且恒定的数字(没有 case 10-100,绝对没有 case <5case x:)。
  • 是语句(switch本身没有值,是条件跳转到语句的一种方式)
  • 与 C 版本不同,将开关的性质视为一种奇怪的 GOTO-esque 构造,从而允许您交错控制结构,例如 do/while 循环通过它实际上是不允许的(幸运的是,我猜)? - 因此,Duff's Device 在 java.
  • 中不合法,也从未合法

最近更新:

与枚举一起:开关中的枚举

Java1.5 引入了枚举,并且由于枚举旨在替换 int 常量,因此它们需要在开关中可用。鉴于枚举值有一个 'ordinal',它是一个 int,实现是微不足道的:switch (someEnum) { case ENUMVAL: }switch(someEnum.ordinal()) { case 1: } 周围的轻糖,其中 1 是 ENUMVAL 的序数值。

仅semi-recent:字符串

在 JDK7 中,添加了 strings-in-switch 支持。相同的原则适用:只有常量,null 不行 - 它是 'fast',因为它实现为跳转 table(与一系列 if/elseif 语句形成对比,后者需要比较对于每一个。如果 none 匹配,跳转 table 只是跳转,使用单个比较,直接跳到右行或到末尾。

现在的新内容 (12+):作为表达式

现在switch可以是一个表达式。就像开关 return 一样。但是,为了使该工作正常进行,整个切换过程中的每个 'path' 都必须 return 某些内容,并且不可能(呵呵)缺少 case 语句;毕竟,表达式应该解析成什么?因此,在这个'mode'中,你一定已经穷尽了所有的选择。有趣的子情况是枚举,你可以在其中 'exhaustive',但在运行时这永远无法保证;如果有人向枚举添加一个值并重新编译枚举并将其放入其中怎么办?现在,以前详尽无遗(涵盖每个选项)的开关不再是:

int y = switch(textyNumber) {
  case "one": yield 1;
  case "two": yield 2;
  default: yield 0;
};

yield 是这里的一种新方法。它很像 'return' - 它从开关 'returns',returning 该值。如果缺少该默认子句,则会出现编译器错误。

枚举的奇怪之处在于,如果您详尽无遗(涵盖每个枚举值),它会编译,但如果您随后添加一个枚举值,请不要使用开关重新编译代码,并尝试抛出一个新的通过创建枚举值,开关抛出 java.lang.IncompatibleClassChangeError。你知道的越多。

箭头语法

因为 'yield' 有点笨拙,仅 one-liner 所需的表达式可能很有用,类似于您可以编写的方式,例如:

Comparator<String> byLength = (a, b) -> a.length() - b.length();

相同的箭头语法现在在开关中是合法的,为了保持一致性,它甚至在 statement-form 开关中也是合法的:

int x = 1;
int y = switch(x) {
   case 1 -> 2;
   default -> 0;
};

switch (y) {
  case 0 -> System.out.println("Interesting");
}

箭头防止漏掉(它暗示 break),并且只接受一个语句。但是一整块也算作一条语句:

switch (y) {
  case 0 -> {
    System.out.println("one");
    System.out.println("two");
  }
  case 1 -> {
    System.out.println("three");
  }
}

只会打印 'one'、'two'。

multi-case

逗号可用于分隔值;这类似于您如何使用条来分隔异常类型(catch (IOException | SQLException e) { ... }。适用于所有形式。

模式匹配

现在我们来看看真正有趣的东西:

record Point(int x, int y) {}

...

Object p = new Point(10, 20);

switch (p) {
case Point(x, y) -> System.out.printf("Point [%d, %d]", x, y);
}

很快就会合法 java!现在 'case' 后面的是 'template'。你能把任何 p 解析到这个模板中吗?如果是,则大小写匹配,并为您填写变量。这适用于 'deconstructable' 类型(目前:仅记录;将来任何类型都可以提供解构函数),以及 instanceof 有点交易:

Object o = someExpression;

switch (o) {
  case Number n -> System.out.println("is a number. intvalue: " + n.intValue());
  case String s -> System.out.println("is a string: " + s.toLowerCase());
}

我认为这涵盖了可用于切换到 java v 17 甚至更高版本的所有更新。

注意:您可以通过关注相应的 openjdk 开发邮件列表,尽早找到这些信息的极其详细信息。这些东西主要在 amber-dev 上可以找到,一些模式匹配的东西可以在 valhalla-dev 上找到,因为它们与记录密切相关,并且记录 o值类型错误(valhalla = java 的值类型,amber = 通用语言更新)。在 java 会议上,通常有人会对此进行细分,reddit 的 /r/java 倾向于 post 当来自 OpenJDK 团队的人(对于这个东西,你正在看 Brian Goetz通常)post 是关于如何设想/实施该功能的重大更新。在 Twitter 上关注 Brian,这也很有帮助。发行说明以及与任何新 java 发行版相关联的伞形 JEP 页面也应提及这些内容以及您随后可以关注的链接。