Switch 表达式与 switch 语句该使用哪一个

问题描述 投票:0回答:1

Java

14
标准化了 switch 语句,并且自 Java
17
以来,它们增强了 switch 表达式以包括模式匹配。

是否有关于何时应使用 switch 语句与 switch 表达式的任何指南?

java switch-statement switch-expression
1个回答
0
投票

我认为你用错了词。基于这样的观念:如果你知道这些术语的含义,你就不会问它;这是显而易见的。

表达式有一个值。 声明则不然。

您什么时候使用其中之一?好吧,当你需要整个 switch 块的结果是“计算一个值”时,then 表达式,否则,statement。示例:

int wheels = switch (vehicleType) {
  case MOTORCYCLE, BICYCLE -> 2;
  case CAR -> 4;
  case CONSTRUCTION_TRUCK -> 6;
};

这个构造具有相当大的优点,它要求完整性:如果

vehicleType
VehicleType
类型的表达式,并且这是一个枚举,并且我们涵盖了所有 4 个可能的值 - 上面的编译。但是,例如,如果
MOPED
是一个选项,则上面的内容将立即出现编译器错误:您需要覆盖 all 的情况(毕竟,否则会发生什么?)。有
default ->
,如果您想选择“如果发生未发现的情况,我只想例外”,您只需添加:

default -> throw new IllegalStateException("Not expected here: " + vehicleType);

但是,我想你可能会感到困惑。因为除了“语句”和“表达式”之外,还有很多东西需要切换。至少涉及3个维度:

语句 v 表达式

在过去,开关本身根本没有价值。你必须做这样的事情:

int wheels;
switch (vehicleType) {
  case BICYCLE:
  case MOTORCYCLE:
    wheels = 2;
    break;
  ... and so on
}

这很烦人 - 有点难看,如果你忘记了

break;
它真的会很糟糕,编译器不会帮助你处理忘记的元素,即使你覆盖了所有内容,编译器也会抱怨
wheel
“可能不会已设置”。

因此,您的第一个答案是:如果您可以用表达式替换语句,您应该始终这样做,它们绝对是优越的

您不必编写单个表达式;你可以写一个块;然后,您可以使用

yield
关键字来提供该值。因此,这个:

case CAR -> 4;

还有这个:

case CAR -> {
  yield 4;
}

是同一件事。但是您可以在第二种形式中添加更多内容,因此仅当您有更多事情要做时才使用它。

箭头 v 冒号

箭头符号是新的;冒号表示法仍然有效并且一直有效。开关表达式要求您使用箭头表示法,但您也可以在语句中使用箭头表示法!

除了使用

->
而不是
:
之外,关键的区别在于冒号表示法“会被忽略”(除非您以
break;
结束正文)并且不需要大括号,而箭头表示法则不需要大括号不会失败并且需要大括号,除非主体适合在一行中,这与 lambda 语法的工作方式相同(其中仅当“主体”是单个表达式或单个语句时才可以省略大括号)。

除非需要失败,否则您应该使用箭头表示法。 很少是这样的情况,所以你实际上应该总是使用箭头表示法!

注意:您可能想知道:如果冒号符号如此无用,为什么 java 首先要有它?愚蠢的设计? - 嗯,也许吧,但是 java 拥有它的原因是因为 C 拥有它,而 java 的设计目标之一是算术代码基本上可以从 C 直接复制粘贴到 java,并且一般语法是熟悉和熟悉的对 C 程序员来说很舒服。这意味着 java 已经复制了一些,让我们宽容地称它们为,呃,odd,语言设计选择。重点是,它奏效了。 Java 是“极少数”与它旨在吸引用户的语言一样/更流行的语言之一。例如,Scala 和 Kotlin 肯定无法像 Java 对 C 所做的那样对 Java 做到这一点。 模式匹配

如果您想使用它,则需要箭头表示法 - 但是,

case

->
之间的东西可以不仅仅是一个值(
case 4 ->
- 这只是一个值)。您可以进行模式匹配。例如,您可以写:
record Point(int x, int y) {}

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

你什么时候用它?当……每当它看起来有用的时候。与大多数编码结构一样,语言规范并不禁止其预期用途的有限域。有 
are

样式指南,但是 Java 领域的样式指南相当旧并且根本没有更新。例如,大多数风格指南要求你要做好准备while

if
等等。但是,它们对 lambda 没有相同的要求。所以,在大多数风格指南中,这是可以的:
list.stream().map(x -> x.foo().bar()).filter(Bar::isNice).toList();

但这不是:

if (list.isEmpty()) throw new IllegalArgumentException("Empty list"); // style violation: Should have braces!

这从表面上看是完全疯狂的,事实上,如果你阅读了样式指南的基本原则,它

疯狂的:对于为什么需要大括号的每一个理由对于 lambda 语法来说都是更糟糕!显然,要么样式指南已经过时,并且应该为所有 lambda 都“要求大括号”,要么其原则过于夸张,并且“始终使用大括号”是不好的样式。意见:是的。第二个片段是很好,“总是大括号”是一个常见的样式原则,它总是错误的,并且根据 lambda 语法,绝对应该被废除。

© www.soinside.com 2019 - 2024. All rights reserved.