Por qué cambiar es más rápido que si

He encontrado muchos libros en Java que dicen que el enunciado de cambio es más rápido que el enunciado else. Pero no encontré en ninguna parte por qué el cambio es más rápido que si .

Ejemplo

Tengo una situación que tengo que elegir cualquiera de los dos elementos que puedo usar de la siguiente manera

switch(item){ case BREAD: //eat Bread break; default: //leave the restaurant } 

o usando una statement if como la siguiente

 if(item== BREAD){ //eat Bread }else{ //leave the restaurant } 

teniendo en cuenta el artículo y BREAD es el valor int constante

En el ejemplo anterior que es más rápido en acción y por qué?

Debido a que existen códigos de bytes especiales que permiten una evaluación eficiente de instrucciones de conmutación cuando hay muchos casos.

Si se implementa con IF-statement, usted tendría un cheque, un salto a la siguiente cláusula, un cheque, un salto a la siguiente cláusula y así sucesivamente. Con el interruptor, la JVM carga el valor para comparar e itera a través de la tabla de valores para encontrar una coincidencia, que es más rápida en la mayoría de los casos.

Una instrucción switch no siempre es más rápida que una instrucción if . Se escala mejor que una larga lista de sentencias if-else , ya que switch puede realizar una búsqueda basada en todos los valores. Sin embargo, para una condición breve, no será más rápido y podría ser más lento.

La JVM actual tiene dos tipos de códigos de bytes de conmutación: LookupSwitch y TableSwitch.

Cada caso en una statement de conmutación tiene un desplazamiento entero, si estos desplazamientos son contiguos (o mayormente contiguos sin espacios grandes) (caso 0: caso 1: caso 2, etc.), entonces se utiliza TableSwitch.

Si los desplazamientos se extienden con espacios grandes (caso 0: caso 400: caso 93748 :, etc.), entonces se usa LookupSwitch.

La diferencia, en resumen, es que TableSwitch se realiza en tiempo constante porque cada valor dentro del rango de valores posibles recibe un desplazamiento de código de bytes específico. Por lo tanto, cuando le das a la statement un desplazamiento de 3, sabe que salta 3 para encontrar la twig correcta.

El interruptor de búsqueda usa una búsqueda binaria para encontrar la twig de código correcta. Esto se ejecuta en el tiempo O (log n), que sigue siendo bueno, pero no el mejor.

Para obtener más información al respecto, consulte aquí: ¿ Diferencia entre LookupSwitch y TableSwitch de JVM?

Entonces, en cuanto a cuál es el más rápido, use este enfoque: si tiene 3 o más casos cuyos valores son consecutivos o casi consecutivos, siempre use un interruptor.

Si tiene 2 casos, use una statement if.

Para cualquier otra situación, es muy probable que el cambio sea más rápido, pero no está garantizado, ya que la búsqueda binaria en LookupSwitch podría llegar a un mal escenario.

Además, tenga en cuenta que la JVM ejecutará optimizaciones de JIT en declaraciones if que intentarán colocar la twig más caliente primero en el código. Esto se llama “Predicción de twig”. Para obtener más información sobre esto, consulte aquí: https://dzone.com/articles/branch-prediction-in-java

Tus experiencias pueden variar No sé si JVM no ejecuta una optimización similar en LookupSwitch, pero he aprendido a confiar en las optimizaciones de JIT y no intentar superar al comstackdor.

En el nivel de código de bytes, la variable sujeto se carga una sola vez en el registro del procesador desde una dirección de memoria en el archivo .class estructurado cargado por Runtime, y esto está en una statement de cambio; mientras que en un enunciado if, el DE que comstack el código produce una instrucción jvm diferente, y esto requiere que cada variable se cargue en los registros, aunque se usa la misma variable que en el siguiente enunciado if anterior. Si conoce la encoding en lenguaje ensamblador, esto sería un lugar común; aunque los cox comstackdos de Java no son bytecode, o código de máquina directo, el concepto condicional de esto sigue siendo consistente. Bueno, traté de evitar un tecnicismo más profundo al explicarlo. Espero haber aclarado y desmitificado el concepto. Gracias.

Si está realizando una cantidad insana de verificaciones como 100+, es posible que desee considerar algo de abstracción.

Tiene paquetes entrantes que van desde los identificadores 0 a 255. Puede usar 150 de ellos. Es posible que desee considerar algo como el siguiente en lugar de un cambio de 150 identificadores.

 Packets[] packets = new Packets[150]; static { packets[0] = new Login(); packets[2] = new Logout(); packets[3] = new GetMessage(); packets[7] = new AddFriend(); packets[9] = new JoinGroupChat(); // etc... not going to finish. } static final byte[] INDEX_LIST = { 0, 2, 3, 7, 9, // etc... Not going to do it, but this will convert packet id to index. }; public void handlePacket(IncomingData data) { int id = data.readByte(); packets[INDEX_LIST[id]].execute(data); } 

También debo señalar que la lista de índices no es realmente necesaria y que, de todos modos, ralentizaría el código. Fue simplemente una sugerencia, por lo que no tiene ubicaciones vacías. Además, para no mencionar esta situación, solo está perdiendo de 106 índices. No estoy 100% seguro, pero creo que cada uno de estos apunta a cero de todos modos por lo que no hay problemas de memoria reales.