当前位置: 首页 > 知识库问答 >
问题:

具有void返回类型的开关表达式

庞意智
2023-03-14

当交换机分支调用void返回类型的方法时,有没有办法强制对所有枚举值进行彻底检查?仅仅为了诱使编译器要求穷尽性而对产量进行硬编码是非常丑陋的。

这是我当前的模式(handle方法具有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; }
};

我想使用表达式的原因是在添加新枚举值但未处理时出现编译错误。

共有3个答案

孔嘉茂
2023-03-14

如果您有在发布主代码之前构建和运行的测试类(例如JUNIT测试用例),那么您可以将一个简单的保护函数放入任何现有的测试类中,用于您要查看的每个枚举:

String checkForEnumChanged(YourEnum guard) {
    return switch (guard) {
        case ORDER -> "OK";
        case INVOICE -> "OK";
        case PAYMENT -> "OK";
    };
}

这意味着您可以将主应用程序代码清除为0 开关样式并在测试类中获取编译错误。

罗心思
2023-03-14

这个问题的陈述有点“XY问题”;你想要的是整体性检查,但你要求它被视为一个表达式,不是因为你想要一个表达式,而是因为你想要表达式罩附带的整体性检查。

添加switch表达式留下的“技术债务”之一是switch语句能够选择switch表达式得到的相同的总体检查。我们不能追溯性地更改关于switch语句的这一点——switch语句始终被允许是部分的——但您是对的,能够进行这种类型的检查是很好的。正如您猜测的那样,将其转换为一个无效的表达式开关是实现这一目标的一种方法,但它确实很难看,更糟糕的是,不容易被发现。在我们的列表中,我们将找到一种方法,允许您重新选择对switch语句进行总体检查。关于这一点,已经在琥珀色规范专家列表上进行了讨论;它与其他几个可能的特性相关,设计讨论仍在进行中。

令狐翰
2023-03-14

也许会产生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);

根据有关性能惩罚的评论,执行基准测试以比较以下场景:

  1. 使用consumer和handle是实例方法
  2. 使用consumer和handle是静态方法
  3. 不使用使用者和句柄是实例方法
  4. 不使用使用者和句柄是静态方法

要查看

  • 使用消费者是否对性能有很大影响

结果是:

# 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

通过观察结果,这4种情况之间没有太大差异。

  • 使用消费者不会对性能产生重大影响。
  • 静态和实例句柄方法之间的性能差异是可以忽略的。

基准测试使用的是:CPU:Intel(R)Core(TM)i7-8750H
内存:16G
JMH版本:1.19
VM版本:JDK 15.0.2

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Thread)
@Warmup(iterations = 30, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 30, time = 500, timeUnit = TimeUnit.MILLISECONDS)
public class SwitchExpressionBenchMark {
    public static void main(String[] args) throws Exception {
        org.openjdk.jmh.Main.main(args);
    }

    @Benchmark
    public void consumerStaticHandle(Blackhole blackhole, InvoiceEvent invoiceEvent) {
        Event event = invoiceEvent;
        Consumer<Event> consumer = switch (event.getEventType()) {
            case ORDER -> e -> staticHandle((OrderEvent) e);
            case INVOICE -> e -> staticHandle((InvoiceEvent) e);
            case PAYMENT -> e -> staticHandle((PaymentEvent) e);
        };
        consumer.accept(event);
    }

    @Benchmark
    public void consumerHandle(Blackhole blackhole, InvoiceEvent invoiceEvent) {
        Event event = invoiceEvent;
        Consumer<Event> consumer = switch (event.getEventType()) {
            case ORDER -> e -> this.handle((OrderEvent) e);
            case INVOICE -> e -> this.handle((InvoiceEvent) e);
            case PAYMENT -> e -> this.handle((PaymentEvent) e);
        };
        consumer.accept(event);
    }

    @Benchmark
    public void noConsumerHandle(Blackhole blackhole, InvoiceEvent invoiceEvent) {
        Event event = invoiceEvent;
        int unused = switch (event.getEventType()) {
            case ORDER -> {
                this.handle((OrderEvent) event);
                yield 0;
            }
            case INVOICE -> {
                this.handle((InvoiceEvent) event);
                yield 0;
            }
            case PAYMENT -> {
                this.handle((PaymentEvent) event);
                yield 0;
            }
        };
    }

    @Benchmark
    public void noConsumerStaticHandle(Blackhole blackhole, InvoiceEvent invoiceEvent) {
        Event event = invoiceEvent;
        int unused = switch (event.getEventType()) {
            case ORDER -> {
                staticHandle((OrderEvent) event);
                yield 0;
            }
            case INVOICE -> {
                staticHandle((InvoiceEvent) event);
                yield 0;
            }
            case PAYMENT -> {
                staticHandle((PaymentEvent) event);
                yield 0;
            }
        };
    }

    private static void staticHandle(PaymentEvent event) {
        doSomeJob();
    }

    private static void staticHandle(InvoiceEvent event) {
        doSomeJob();
    }

    private static void staticHandle(OrderEvent event) {
        doSomeJob();
    }

    private void handle(PaymentEvent event) {
        doSomeJob();
    }

    private void handle(InvoiceEvent event) {
        doSomeJob();
    }

    private void handle(OrderEvent event) {
        doSomeJob();
    }

    private static void doSomeJob() {
        Blackhole.consumeCPU(16);
    }

    private enum EventType {
        ORDER, INVOICE, PAYMENT
    }

    public static class Event {
        public EventType getEventType() {
            return eventType;
        }

        public void setEventType(EventType eventType) {
            this.eventType = eventType;
        }

        private EventType eventType;

        public double getD() {
            return d;
        }

        public void setD(double d) {
            this.d = d;
        }


        private double d;
    }

    public static class OrderEvent extends Event {
    }

    @State(Scope.Thread)
    public static class InvoiceEvent extends Event {
        @Setup(Level.Trial)
        public void doSetup() {
            this.setEventType(EventType.INVOICE);
        }
    }

    public static class PaymentEvent extends Event {
    }
}
 类似资料:
  • 我已经为使用者接口尝试了类似这样的lambda表达式,它没有问题。其他一些lambda表达式不起作用,因为它们返回一些东西,如。 编译和执行没有问题。 所以我遇到的问题是,我认为像这样的lambda表达式总是等效于,所以我希望编译器会给我一个错误,因为您不能从使用者接口返回(或任何其他类型)。显然,编译器正在将lambda表达式转换为一个方法,如果没有return语句,并且调用方法而不实际返回值。

  • 我不断地得到错误 在终端上编译时。 在switch语句的末尾。这是在用终端编译的时候。

  • 我有下面的课,我试图测试。我遇到问题的方法是,因为我试图存根/模拟行为,然后在测试中验证行为。

  • 我有一个关于显示void类型的返回值的问题。因此trimLines是一个void类型的方法。我不明白如何显示void类型的方法,因为该方法没有返回任何东西,所以没有任何东西可以显示。由于采用字符串类型,这将导致错误。

  • 我有一个静态的通用FormBuilder超文本标记语言助手方法(HTMLHelper类上的扩展方法),它接受视图模型类型的通用参数,然后当从数据库传递一个或多个字符串属性名称时,生成一个超文本标记语言形式在ASP. NET MVC 5.1 with. NET 4.5中。 我有一个公共方法来生成表单,还有单独的私有方法来生成表单中的“模块”部分,然后渲染其中的每个字段。类型参数从上到下沿此链传递。

  • 将异常获取为 :lambda表达式中的返回类型错误: