arb*_*ark 30 java void switch-statement switch-expression java-16
当 switch 分支调用具有 void 返回类型的方法时,有没有办法强制对所有枚举值进行彻底检查?仅仅为了诱使编译器要求穷举而对产量进行硬编码是非常丑陋的。
这是我当前的模式(句柄方法具有 void 返回类型)
int unused = switch (event.getEventType()) {
case ORDER -> { handle((OrderEvent) event); yield 0; }
case INVOICE -> { handle((InvoiceEvent) event); yield 0; }
case PAYMENT -> { handle((PaymentEvent) event); yield 0; }
};
Run Code Online (Sandbox Code Playgroud)
我想使用表达式的原因是在添加新枚举值但未处理时出现编译错误。
sam*_*cde 21
也许 yield a Consumerof Event,所以你产生了一些有用的东西,权衡是多一行consumer.accept。
Consumer<Event> consumer = switch (event.getEventType()) {
case ORDER -> e -> handle((OrderEvent) e);
case INVOICE -> e -> handle((InvoiceEvent) e);
case PAYMENT -> e -> handle((PaymentEvent) e);
};
consumer.accept(event);
Run Code Online (Sandbox Code Playgroud)
根据有关性能损失的评论,执行基准测试以比较以下场景:
查看
handle方法和实例方法有什么区别吗?结果是:
# Run complete. Total time: 00:20:30
Benchmark Mode Cnt Score Error Units
SwitchExpressionBenchMark.consumerHandle thrpt 300 49343.496 ± 91.324 ops/ms
SwitchExpressionBenchMark.consumerStaticHandle thrpt 300 49312.273 ± 112.630 ops/ms
SwitchExpressionBenchMark.noConsumerHandle thrpt 300 49353.232 ± 106.522 ops/ms
SwitchExpressionBenchMark.noConsumerStaticHandle thrpt 300 49496.614 ± 122.916 ops/ms
Run Code Online (Sandbox Code Playgroud)
通过观察结果,4种场景之间没有太大区别。
handle方法和实例方法之间的性能差异是可以忽略的。基准测试使用:
CPU:Intel(R) Core(TM) i7-8750H
内存:16G
JMH 版本:1.19
VM 版本:JDK 15.0.2
Consumer<Event> consumer = switch (event.getEventType()) {
case ORDER -> e -> handle((OrderEvent) e);
case INVOICE -> e -> handle((InvoiceEvent) e);
case PAYMENT -> e -> handle((PaymentEvent) e);
};
consumer.accept(event);
Run Code Online (Sandbox Code Playgroud)
Bri*_*etz 16
问题的陈述有点像“XY问题”;您想要的是完整性检查,但您要求将其视为表达式,不是因为您想要表达式,而是因为您想要表达式罩附带的完整性检查。
添加 switch 表达式后留下的“技术债务”项目之一是 switch语句能够选择与 switch 表达式相同的总体检查。我们无法追溯更改关于 switch 语句的这一点——switch 语句总是被允许是部分的——但是你是对的,能够进行这种类型检查是很好的。正如您所猜测的那样,将它变成一个无效的表情开关是一种方法,但它确实很丑,更糟糕的是,不容易被发现。在我们的列表中,可以找到一种方法来允许您选择重新进行 switch 语句的总体检查。已经在amber-spec-experts名单上讨论过这个问题;它与其他几个可能的功能有关,设计讨论仍在进行中。
如果您有在发布主代码之前构建和运行的测试类(比如 JUNIT 测试用例),那么您可以将一个简单的保护函数放入任何现有的测试类中,以查看您想要查看的每个枚举:
String checkForEnumChanged(YourEnum guard) {
return switch (guard) {
case ORDER -> "OK";
case INVOICE -> "OK";
case PAYMENT -> "OK";
};
}
Run Code Online (Sandbox Code Playgroud)
这意味着yield 0;当编辑枚举值时,您可以使您的主应用程序代码远离switch 样式,并在测试类中得到编译错误。