Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

220
Vistas
Cambiar expresión con tipo de retorno nulo

¿Hay alguna forma de forzar una verificación exhaustiva de todos los valores de enumeración cuando el interruptor se bifurca en métodos de llamada con tipo de retorno nulo? Es bastante feo codificar un rendimiento solo para convencer al compilador de que exija exhaustividad.

Este es mi patrón actual (los métodos de manejo tienen un tipo de retorno nulo)

 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; } };

La razón por la que quiero usar una expresión es para obtener un error de compilación cuando se agrega un nuevo valor de enumeración y no se maneja.

over 4 years ago · Santiago Trujillo
5 Respuestas
Responde la pregunta

0

Tal vez produzca un Consumer of Event , por lo que produce algo útil, la compensación es una línea más para 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);

Continúe si le preocupa el rendimiento

Según el comentario sobre la penalización de rendimiento, se realiza un punto de referencia para comparar los siguientes escenarios:

  1. El uso del consumidor y el identificador es un método de instancia
  2. El uso del consumidor y el identificador es un método estático.
  3. No usar consumidor y manejar es método de instancia
  4. No usar consumidor y manejar es un método estático

Para ver

  • ¿El uso de Consumer tiene un gran impacto en el rendimiento?
  • ¿Hay alguna diferencia para el método de handle estático y de instancia?

Y el resultado es:

 # 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

Al observar el resultado, no hay mucha diferencia entre los 4 escenarios.

  • El uso de Consumer no tiene un impacto significativo en el rendimiento.
  • La diferencia de rendimiento entre el método de handle estático y de instancia es despreciable.

El benchmark se realiza con:
UPC: Intel(R) Core(TM) i7-8750H
Memoria: 16G
Versión JMH: 1.19
Versión de máquina virtual: 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 { } }
over 4 years ago · Santiago Trujillo Denunciar

0

Si tiene clases de prueba (por ejemplo, casos de prueba JUNIT) que crea y ejecuta antes de publicar su código principal, entonces puede colocar una función de protección simple en cualquier clase de prueba existente para cada enumeración que desee ver:

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

Esto significa que puede mantener el código de su aplicación principal libre del yield 0; estilo de interruptor y obtiene un error de compilación en las clases de prueba cuando se editan los valores de enumeración.

over 4 years ago · Santiago Trujillo Denunciar

0

La declaración de la pregunta es un poco un "problema XY"; lo que quieres es la verificación de la totalidad, pero estás pidiendo que se trate como una expresión, no porque quieras una expresión, sino porque quieres la verificación de la totalidad que viene con la expresión.

Uno de los elementos de "deuda técnica" que quedan de la adición de expresiones de cambio es la capacidad de las sentencias de cambio de optar por la misma verificación de totalidad que obtienen las expresiones de cambio. No pudimos cambiar retroactivamente esto acerca de las declaraciones de cambio (siempre se ha permitido que las declaraciones de cambio sean parciales), pero tiene razón en que sería bueno poder obtener este tipo de verificación de tipo. Como supones, convertirlo en un interruptor de expresión vacía es una forma de llegar allí, pero de hecho es feo y, lo que es peor, no será fácil de descubrir. Está en nuestra lista encontrar una manera de permitirle volver a optar por la verificación de la totalidad para las declaraciones de cambio. Ha habido discusiones en la lista amber-spec-experts sobre esto; está relacionado con varias otras características posibles, y las discusiones de diseño aún están en curso.

over 4 years ago · Santiago Trujillo Denunciar

0

Agregar un delegado

Agregue un método de delegado para reenviar la solicitud y devolver un tipo Void

 public class SwitchTest { enum EventType { ORDER, INVOICE, PARCELDELIVERY } interface Event { EventType getType(); } static class OrderType implements Event { @Override public EventType getType() { return EventType.ORDER; } } static class InvoiceType implements Event { @Override public EventType getType() { return EventType.INVOICE; } } static void handle(Event e) { System.out.println(e.getType()); } static Void switchExpressionDelegate(Event e) { handle(e); return null; } public static void main(String[] args) { Event event = new OrderType(); Void nullNoop = switch (event.getType()) { case ORDER -> switchExpressionDelegate(event); case INVOICE -> switchExpressionDelegate(event); case PARCELDELIVERY -> switchExpressionDelegate(event); }; } }

tipo exacto

Suponiendo que el método handle tiene un tipo exacto, se debe agregar una jerarquía paralela de métodos delegados. (aunque esto no se ve bien)

 static Void switchExpressionDelegate(OrderType e) { handle(e); return null; } static Void switchExpressionDelegate(InvoiceType e) { handle(e); return null; } public static void main(String[] args) { Event event = new OrderType(); Void nullNoop = switch (event.getType()) { case ORDER -> switchExpressionDelegate((OrderType) event); case INVOICE -> switchExpressionDelegate((InvoiceType) event); case PARCELDELIVERY -> switchExpressionDelegate((OrderType) event); // can throw error in an actual implementation }; }

Adaptador

Si agregar nuevas clases es una opción, entonces se pueden agregar clases de adaptador

Todo lo anterior se ve a su alrededor

Como lo señala otra respuesta de sambabcde , la mejor opción parece ser usar un Consumidor

 public static void main(String[] args) { Event event = new OrderType(); Consumer<Void> nullNoop = switch (event.getType()) { case ORDER -> e -> handle((OrderType) event); case INVOICE -> e -> handle((InvoiceType) event); case PARCELDELIVERY -> e -> handle((OrderType) event); }; nullNoop.accept(null); }
over 4 years ago · Santiago Trujillo Denunciar

0

¿Qué hay de ejecutable:

 Runnable limitOperationRunnable = switch (limitOperation) { case INSERT -> () -> ...; case UPDATE -> () -> ...; case DELETE -> () -> ...; }; limitOperationRunnable.run();
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda