可以使用逗号连接 switch 语句的两种情况吗

Sha*_*_01 0 java switch-statement

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

switch (element) {
   case hi:
   case hello:
      //do something here
      break;
}
Run Code Online (Sandbox Code Playgroud)

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

switch (element) {
   case hi, hello:
      //do something here
      break;
}
Run Code Online (Sandbox Code Playgroud)

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

rzw*_*oot 7

最近版本的 java(12 及更高版本)已经在switch. 现在有很多种形式。其中一些形式有一个基本原则,强烈表明一些新的语法特征很重要,并且为了一致性,如果其他形式也可以允许该特征,那么其他形式也会更新。

历史

最初的 java 1.0 switch 是 C 的直接副本(这解释了它们完全奇怪和愚蠢的语法;这就是 C 所拥有的,而 java 的设计是为了让 C 程序员感到舒适。我们可以抱怨这样一个事实,即这意味着语法是愚蠢的,但很难否认 C 风格语法,无论看起来多么疯狂,已经占领了这个星球,可以说,C、C#、Java 和 Javascript 加在一起占据了“市场”的很大一部分) 。

它:

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

最近更新:

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

Java1.5 引入了枚举,并且由于枚举旨在取代 int 常量,因此它们需要可在 switch 中使用。考虑到枚举值有一个 int 的“序数”,实现很简单:switch (someEnum) { case ENUMVAL: }是 周围的简单糖switch(someEnum.ordinal()) { case 1: },其中 1 是 ENUMVAL 的序数值。

仅半新近:字符串

在 JDK7 中,添加了 strings-in-switch 支持。同样的原则适用:只有常量,null 是不行的 - 而且它“快”,因为它实现为跳转表(与一系列 if/elseif 语句相反,后者需要对每个语句进行比较。跳转表只是使用单次比较直接跳转到右侧行,如果没有匹配则跳转到末尾。

现在新东西(12+):作为表达式

如今 switch 可以是一个表达式。就像这样,开关返回一个东西。然而,为了使其工作,整个开关中的每条“路径”都必须返回一些东西,并且不可能出现缺少case语句的情况(呵呵);毕竟,表达式应该解析为什么呢?因此,在这种“模式”下,您必须用尽所有选项。有趣的子情况是枚举,您可以在其中“详尽”,但在运行时永远无法保证这一点;如果有人向枚举添加一个值并重新编译该枚举并将其放入其中怎么办?现在,以前的详尽(涵盖每个选项)开关不再是:

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

yield这是一种新方法。它很像“返回”——它从开关“返回”,返回该值。如果缺少默认子句,则会出现编译器错误。

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

箭头语法

因为“yield”有点笨拙,它对于仅用一行行表达所需的表达式可能很有用,类似于您可以编写的方式,例如:

Comparator<String> byLength = (a, b) -> a.length() - b.length();
Run Code Online (Sandbox Code Playgroud)

现在,相同的箭头语法在开关中是合法的,并且为了一致性,它甚至在语句形式开关中也是合法的:

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

switch (y) {
  case 0 -> System.out.println("Interesting");
}
Run Code Online (Sandbox Code Playgroud)

该箭头可防止失败(它暗示break),并且仅采用一个语句。但一整块也算作一个语句:

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

只会打印“一”、“二”。

多案例

可以使用逗号来分隔值;这类似于使用条形来分隔异常类型(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);
}
Run Code Online (Sandbox Code Playgroud)

java很快就会合法化!现在,“案例”后面的东西是“模板”。你能把任何p解析到这个模板中吗?如果是,则大小写匹配,并且会为您填写变量。这适用于“可解构”类型(当前:仅记录;将来任何类型都可以提供解构函数),以及一个实例:

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());
}
Run Code Online (Sandbox Code Playgroud)

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

注意:您可以通过关注相应的 openjdk 开发邮件列表,尽早找到此信息的极其详细信息。这些东西主要在 amber-dev 上找到,由于与记录密切相关,并且记录与值类型重叠(valhalla = java 的值类型,amber = 通用语言更新),因此在 valhalla-dev 上找到了一些模式匹配的东西)。在 Java 会议上,有人通常会给出这个情况的详细说明,/r/java当 OpenJDK 团队的某个人(对于这个东西,你通常会看到 Brian Goetz)发布有关如何设想该功能的重大更新时,Reddit 往往会发布它/已实施。在 Twitter 上关注 Brian,这也有帮助。发行说明以及与任何新的 java 版本相关的 JEP 页面也应该提及这些内容,并提供您可以关注的链接。