Java
14
标准化了 switch 语句,并且自 Java 17
以来,它们增强了 switch 表达式以包括模式匹配。
是否有关于何时应使用 switch 语句与 switch 表达式的任何指南?
我认为你用错了词。基于这样的观念:如果你知道这些术语的含义,你就不会问它;这是显而易见的。
表达式有一个值。 声明则不然。
您什么时候使用其中之一?好吧,当你需要整个 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个维度:
在过去,开关本身根本没有价值。你必须做这样的事情:
int wheels;
switch (vehicleType) {
case BICYCLE:
case MOTORCYCLE:
wheels = 2;
break;
... and so on
}
这很烦人 - 有点难看,如果你忘记了
break;
它真的会很糟糕,编译器不会帮助你处理忘记的元素,即使你覆盖了所有内容,编译器也会抱怨 wheel
“可能不会已设置”。
因此,您的第一个答案是:如果您可以用表达式替换语句,您应该始终这样做,它们绝对是优越的。
您不必编写单个表达式;你可以写一个块;然后,您可以使用
yield
关键字来提供该值。因此,这个:
case CAR -> 4;
还有这个:
case CAR -> {
yield 4;
}
是同一件事。但是您可以在第二种形式中添加更多内容,因此仅当您有更多事情要做时才使用它。
箭头符号是新的;冒号表示法仍然有效并且一直有效。开关表达式要求您使用箭头表示法,但您也可以在语句中使用箭头表示法!
除了使用
->
而不是 :
之外,关键的区别在于冒号表示法“会被忽略”(除非您以 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 语法,绝对应该被废除。