Java >> Java tutorial >  >> Tag >> return

Skift udtryk med ugyldig returtype

Måske give en Consumer af Event , så du giver noget nyttigt, er afvejningen en linje mere for 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);

Fortsæt, hvis du bekymrer dig om ydeevne

Baseret på kommentaren om præstationsstraf udføres et benchmark for at sammenligne følgende scenarier:

  1. Brug af forbruger og håndtering er instansmetode
  2. Brug af forbruger og håndtag er en statisk metode
  3. Ikke bruger forbruger og håndtere er instansmetode
  4. At bruge forbruger og håndtag er en statisk metode

At se

  • Har brug af Consumer stor effekt på ydeevnen?
  • Er der nogen forskel for statisk og instans handle metode?

Og resultatet er:

# Run complete. Total time: 00:08:08

Benchmark                                          Mode  Cnt     Score     Error  Units
SwitchExpressionBenchMark.consumerHandle          thrpt   20  5643.921 ±  79.075  ops/s
SwitchExpressionBenchMark.consumerStaticHandle    thrpt   20  5549.207 ± 115.133  ops/s
SwitchExpressionBenchMark.noConsumerHandle        thrpt   20  5616.466 ±  23.528  ops/s
SwitchExpressionBenchMark.noConsumerStaticHandle  thrpt   20  5635.814 ±   7.611  ops/s

Ved at observere resultatet,

  • Brug af Consumer har ikke stor effekt på ydeevnen.
  • At bruge Consumer med statisk metode er hurtigere end instansmetoden, følg kommentaren fra Brian Goetz og Holger.

Benchmark udføres med:
CPU:Intel(R) Core(TM) i7-8750H
Hukommelse:16G
JMH version:1.19
VM-version:JDK 15.0.2

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Mode;

import java.util.function.Consumer;

public class SwitchExpressionBenchMark {
    public static void main(String[] args) throws Exception {
        org.openjdk.jmh.Main.main(args);
    }

    @Fork(value = 1, warmups = 2)
    @BenchmarkMode(Mode.Throughput)
    @Benchmark
    public void consumerStaticHandle() {
        Event event = new InvoiceEvent();
        event.setEventType(EventType.INVOICE);
        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);
    }

    @Fork(value = 1, warmups = 2)
    @BenchmarkMode(Mode.Throughput)
    @Benchmark
    public void consumerHandle() {
        Event event = new InvoiceEvent();
        event.setEventType(EventType.INVOICE);
        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);
    }

    @Fork(value = 1, warmups = 2)
    @BenchmarkMode(Mode.Throughput)
    @Benchmark
    public void noConsumerHandle() {
        Event event = new InvoiceEvent();
        event.setEventType(EventType.INVOICE);
        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;
            }
        };
    }

    @Fork(value = 1, warmups = 2)
    @BenchmarkMode(Mode.Throughput)
    @Benchmark
    public void noConsumerStaticHandle() {
        Event event = new InvoiceEvent();
        event.setEventType(EventType.INVOICE);
        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 double doSomeJob() {
        double d = 0;
        for (int i = 0; i < 10000; i++) {
            d += Math.pow(Math.PI, i);
        }
        return d;
    }

    private enum EventType {
        ORDER, INVOICE, PAYMENT
    }

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

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

        private EventType eventType;
    }

    private static class OrderEvent extends Event {
    }

    private static class InvoiceEvent extends Event {
    }

    private static class PaymentEvent extends Event {
    }
}

Stillingen af ​​spørgsmålet er lidt af et "XY-problem"; det, du ønsker, er totalitetskontrol, men du beder om, at det skal behandles som et udtryk, ikke fordi du vil have et udtryk, men fordi du vil have den helhedskontrol, der følger med expression-hood.

En af de elementer af "teknisk gæld", der er tilbage fra tilføjelsen af ​​skifteudtryk, er muligheden for skifte udsagn at tilmelde sig den samme helhedskontrol, som skifteudtryk får. Vi kunne ikke med tilbagevirkende kraft ændre dette om switch-sætninger -- switch-udsagn har altid fået lov til at være delvise -- men du har ret i, at det ville være rart at kunne få denne form for typekontrol. Som du antager, er det en måde at komme dertil at omdanne den til en void expression switch, men den er faktisk grim, og endnu værre, vil den ikke være let at finde. Det er på vores liste at finde en måde, hvorpå du kan vælge tilbage til totalkontrol for switch-udsagn. Der har været diskussioner om amber-spec-experts liste over dette; det er relateret til flere andre mulige funktioner, og designdiskussioner er stadig i gang.


Hvis du har testklasser (f.eks. JUNIT-testcases), som du bygger og kører, før du frigiver din hovedkode, så kan du droppe en simpel vagtfunktion i enhver eksisterende testklasse for hver enum, du vil se:

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

Dette betyder, at du kan holde din hovedapplikationskode fri af yield 0; switch-stil og få en kompileringsfejl i testklasserne, når enum-værdierne redigeres.


Java tag