Muchos libros de Java describen la switch
declaración como más rápida que la if else
declaración. Pero no descubrí en ninguna parte por qué el cambio es más rápido que si .
Ejemplo
Tengo una situación en la que tengo que elegir un elemento de dos. Puedo usar cualquiera de los dos
switch (item) {
case BREAD:
//eat Bread
break;
default:
//leave the restaurant
}
o
if (item == BREAD) {
//eat Bread
} else {
//leave the restaurant
}
considerando item y BREAD es un valor int constante.
En el ejemplo anterior, ¿cuál es la acción más rápida y por qué?
java
switch-statement
Jacob van Lingen
fuente
fuente
Respuestas:
Porque hay códigos de bytes especiales que permiten una evaluación eficiente de las declaraciones de conmutación cuando hay muchos casos.
Si se implementa con declaraciones IF, tendría un control, un salto a la siguiente cláusula, un control, un salto a la siguiente cláusula, etc. Con el interruptor, la JVM carga el valor para comparar y recorre la tabla de valores para encontrar una coincidencia, lo que es más rápido en la mayoría de los casos.
fuente
switch
puede no traducirse en unatableswitch
instrucción de código de bytes; puede convertirse en unalookupswitch
instrucción que se desempeñe de manera similar a un if / else (ii) incluso lastableswitch
instrucciones de un código de bytes pueden ser compiladas en una serie de if / else por el JIT, dependiendo de los factores como el número decase
s.tableswitch
vsloopuswitch
: stackoverflow.com/questions/10287700/…Una
switch
declaración no siempre es más rápida que unaif
declaración. Se escala mejor que una larga lista deif-else
declaraciones, ya queswitch
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.fuente
switch
serían más claras, si no más rápidas.La JVM actual tiene dos tipos de códigos de bytes de conmutación: LookupSwitch y TableSwitch.
Cada caso en una instrucción switch tiene un desplazamiento entero, si estos desplazamientos son contiguos (o en su mayoría contiguos sin espacios grandes) (caso 0: caso 1: caso 2, etc.), entonces se usa TableSwitch.
Si las compensaciones se extienden con grandes espacios (caso 0: caso 400: caso 93748 :, etc.), se utiliza LookupSwitch.
La diferencia, en resumen, es que TableSwitch se realiza en tiempo constante porque a cada valor dentro del rango de valores posibles se le asigna un desplazamiento de código de byte específico. Por lo tanto, cuando le da a la declaración un desplazamiento de 3, sabe que debe saltar 3 para encontrar la rama correcta.
El interruptor de búsqueda utiliza una búsqueda binaria para encontrar la rama de código correcta. Esto se ejecuta en tiempo O (log n), que sigue siendo bueno, pero no el mejor.
Para obtener más información sobre esto, consulte aquí: ¿ Diferencia entre LookupSwitch y TableSwitch de JVM?
En cuanto a cuál es el más rápido, utilice este enfoque: si tiene 3 o más casos cuyos valores son consecutivos o casi consecutivos, utilice siempre un interruptor.
Si tiene 2 casos, use una declaración if.
Para cualquier otra situación, lo más probable es que el cambio sea más rápido, pero no está garantizado, ya que la búsqueda binaria en LookupSwitch podría tener un mal escenario.
Además, tenga en cuenta que la JVM ejecutará optimizaciones JIT en declaraciones if que intentarán colocar la rama más activa primero en el código. Esto se llama "Predicción de ramas". 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 la JVM no ejecuta una optimización similar en LookupSwitch, pero he aprendido a confiar en las optimizaciones de JIT y a no intentar burlarme del compilador.
fuente
switch
una función de lenguaje aún más poderosa. La coincidencia de patrones, por ejemplo, permitiráinstanceof
búsquedas mucho más fluidas y eficaces. Sin embargo, creo que es seguro asumir que para escenarios básicos de switch / if, la regla que mencioné aún se aplicará.Entonces, si planea tener muchos paquetes, la memoria no es realmente un gran costo en estos días y los arreglos son bastante rápidos. Tampoco puede confiar en una declaración de cambio para generar automáticamente una tabla de salto y, como tal, es más fácil generar el escenario de la tabla de salto usted mismo. Como puede ver en el siguiente ejemplo, asumimos un máximo de 255 paquetes.
Para obtener el resultado a continuación, necesita abstracción ... no voy a explicar cómo funciona, así que espero que lo entienda.
Actualicé esto para establecer el tamaño del paquete en 255 si necesita más, entonces tendrá que hacer una verificación de límites para (id <0) || (id> longitud).
Editar ya que uso mucho una tabla de salto en C ++ ahora mostraré un ejemplo de una tabla de salto de puntero de función. Este es un ejemplo muy genérico, pero lo ejecuté y funciona correctamente. Tenga en cuenta que debe establecer el puntero en NULL, C ++ no hará esto automáticamente como en Java.
También otro punto que me gustaría mencionar es el famoso Divide and Conquer. Por lo tanto, mi idea de matriz de 255 anterior podría reducirse a no más de 8 declaraciones if como el peor de los casos.
Es decir, pero tenga en cuenta que se vuelve complicado y difícil de administrar rápidamente y mi otro enfoque es generalmente mejor, pero esto se utiliza en los casos en que las matrices simplemente no lo cortan. Debe averiguar su caso de uso y cuándo funciona mejor cada situación. Del mismo modo que no querría utilizar ninguno de estos enfoques si solo tiene unos pocos controles.
fuente
0 <= id < packets.length
y asegurarsepackets[id]!=null
y luego hacerlopackets[id].execute(data)
?En el nivel de código de bytes, la variable sujeto se carga solo una vez en el registro del procesador desde una dirección de memoria en el archivo estructurado .class cargado por Runtime, y esto es en una declaración de cambio; mientras que en una instrucción if, su DE de compilación de código produce una instrucción jvm diferente, y esto requiere que cada variable se cargue en los registros aunque se use la misma variable que en la siguiente instrucción if precedente. Si conoce la codificación en lenguaje ensamblador, esto sería un lugar común; aunque los cox compilados en java no son bytecode, o código de máquina directo, el concepto condicional del mismo sigue siendo consistente. Bueno, traté de evitar tecnicismos más profundos al explicar. Espero haber dejado el concepto claro y desmitificado. Gracias.
fuente