studio programacion móviles imagenes desarrollo curso aplicaciones java pmd

java - programacion - Eficiencia: cambiar las declaraciones si las declaraciones



imagenes java eclipse (4)

PMD me dice

Un interruptor con menos de 3 ramas es ineficiente, use una instrucción if en su lugar.

¿Porqué es eso? ¿Por qué 3? ¿Cómo definen la eficiencia?


¿Porqué es eso?

Se utilizan diferentes secuencias de instrucciones cuando el compilador JIT compila (finalmente) el código nativo en código nativo. Un interruptor se implementa mediante una secuencia de instrucciones nativas que realizan una rama indirecta. (La secuencia generalmente carga una dirección de una tabla y luego se bifurca a esa dirección). Un if / else se implementa como instrucciones que evalúan la condición (probablemente una instrucción de comparación) seguida de una instrucción de bifurcación condicional.

¿Por qué 3?

Es una observación empírica, supongo que en base al análisis de las instrucciones de código nativo generadas y / o la evaluación comparativa. (O posiblemente no. Para estar absolutamente seguro, debe preguntar al / los autor (es) de esa regla de PMD cómo derivaron ese número).

¿Cómo definen la eficiencia?

Tiempo necesario para ejecutar las instrucciones.

Personalmente, estoy en desacuerdo con esta regla ... o más precisamente con el mensaje. Creo que debería decir que una sentencia if / else es más simple y más legible que un switch con 2 casos. El problema de la eficiencia es secundario, y probablemente irrelevante.


Aunque hay ganancias menores de eficiencia cuando se usa un interruptor en comparación con el uso de una sentencia if, esas ganancias serían despreciables en la mayoría de las circunstancias. Y cualquier escáner de código fuente que valga la pena reconocería que micro-optimizations son secundarias a la claridad del código.

Están diciendo que una instrucción if es más fácil de leer y ocupa menos líneas de código que una instrucción switch si el interruptor es significativamente corto.

Desde el sitio web de PMD :

TooFewBranchesForASwitchStatement: las instrucciones de cambio se utilizan para admitir comportamientos de bifurcación complejos. El uso de un conmutador para solo unos pocos casos no es aconsejable, ya que los conmutadores no son tan fáciles de entender como las afirmaciones if-then. En estos casos, use la declaración theif-then para aumentar la legibilidad del código.


Creo que tiene que ver con la forma en que se compila un switch y if / else.

Digamos que se necesitan 5 cálculos para procesar una instrucción de cambio. Digamos que una sentencia if requiere dos cálculos. Menos de 3 opciones en su conmutador equivaldrían a 4 cálculos en ifs frente a 5 en conmutadores. Sin embargo, la sobrecarga permanece constante en un conmutador, por lo que si tiene 3 opciones, ifs se procesaría 3 * 2, y 5 aún para el conmutador.

Las ganancias al observar millones de cálculos son extremadamente insignificantes. Es más una cuestión de "esta es la mejor manera de hacerlo" en lugar de cualquier cosa que pueda afectarte. Solo lo haría en algo que realice ciclos en esa función millones de veces en una iteración bastante.


Debido a que una instrucción de switch se compila con dos instrucciones especiales de JVM que son el lookupswitch y el tableswitch . Son útiles cuando se trabaja con muchos casos, pero causan una sobrecarga cuando tiene pocas sucursales.

En if/else lugar, una declaración if/else se compila en las típicas cadenas de je jne ... que son más rápidas pero que requieren muchas más comparaciones cuando se usan en una larga cadena de sucursales.

Puede ver la diferencia mirando el código de bytes, en cualquier caso, no me preocuparía por estos problemas, si algo pudiera convertirse en un problema, entonces JIT se encargará de ello.

Ejemplo práctico:

switch (i) { case 1: return "Foo"; case 2: return "Baz"; case 3: return "Bar"; default: return null; }

se compila en:

L0 LINENUMBER 21 L0 ILOAD 1 TABLESWITCH 1: L1 2: L2 3: L3 default: L4 L1 LINENUMBER 23 L1 FRAME SAME LDC "Foo" ARETURN L2 LINENUMBER 24 L2 FRAME SAME LDC "Baz" ARETURN L3 LINENUMBER 25 L3 FRAME SAME LDC "Bar" ARETURN L4 LINENUMBER 26 L4 FRAME SAME ACONST_NULL ARETURN

Mientras

if (i == 1) return "Foo"; else if (i == 2) return "Baz"; else if (i == 3) return "Bar"; else return null;

se compila en

L0 LINENUMBER 21 L0 ILOAD 1 ICONST_1 IF_ICMPNE L1 L2 LINENUMBER 22 L2 LDC "Foo" ARETURN L1 LINENUMBER 23 L1 FRAME SAME ILOAD 1 ICONST_2 IF_ICMPNE L3 L4 LINENUMBER 24 L4 LDC "Baz" ARETURN L3 LINENUMBER 25 L3 FRAME SAME ILOAD 1 ICONST_3 IF_ICMPNE L5 L6 LINENUMBER 26 L6 LDC "Bar" ARETURN L5 LINENUMBER 28 L5 FRAME SAME ACONST_NULL ARETURN