PMD
me diceEficiencia: Interruptor declaraciones sobre si las declaraciones
Un interruptor con menos de 3 ramas es ineficiente, el uso de una sentencia if lugar.
¿Por qué es eso? ¿Por qué 3? ¿Cómo definen la eficiencia?
PMD
me diceEficiencia: Interruptor declaraciones sobre si las declaraciones
Un interruptor con menos de 3 ramas es ineficiente, el uso de una sentencia if lugar.
¿Por qué es eso? ¿Por qué 3? ¿Cómo definen la eficiencia?
Porque una instrucción switch
se compila con dos instrucciones especiales de JVM que son lookupswitch
y tableswitch
. Son útiles cuando se trabaja con muchos casos, pero causan una sobrecarga cuando tienes pocas ramas.
En su lugar, una declaración if/else
se compila en las típicas je
jne
... cadenas que son más rápidas pero requieren muchas más comparaciones cuando se usan en una larga cadena de ramas.
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, 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
Gracias Jack. Esta es una respuesta maravillosa. En una nota lateral, ¿qué usaste para ver los archivos '.class'? – JAM
Es un complemento para Eclipse, si no recuerdo mal debería ser éste: http://andrei.gmxhome.de/bytecode/index.html – Jack
@JAM: creo que también puede usar [javap] (http: // docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/javap.html). – RanRag
Aunque hay ganancias de eficiencia menores al usar un conmutador en comparación con el uso de un enunciado if, esas ganancias serían insignificantes en la mayoría de las circunstancias. Y cualquier escáner de código fuente que valga la pena reconocerá que micro-optimizations son secundarios a la claridad del código.
Dicen 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 cambio es significativamente corto.
Desde el PMD website:
TooFewBranchesForASwitchStatement: declaraciones del interruptor son indentado para ser utilizado para apoyar el comportamiento de ramificación compleja. No es aconsejable utilizar un conmutador en unos pocos casos, ya que los conmutadores no son tan fáciles de entender como las declaraciones if-then. En estos casos, use la instrucción if-then para aumentar la legibilidad del código.
Creo que tiene que ver con la forma en que se compila un interruptor y un if/else.
Digamos que se necesitan 5 cálculos para procesar una declaración de cambio. Digamos que una instrucción if toma dos cálculos. Menos de 3 opciones en su interruptor equivaldrían a 4 cómputos en ifs vs 5 en switches. Sin embargo, la sobrecarga permanece constante en un conmutador, por lo que si tiene 3 opciones, ifs sería 3 * 2 procesado, vs 5 todavía 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 afectarlo. Solo lo haría en algo que ciclos de esa función millones de veces en una iteración bastante.
¿Por qué es eso?
Se utilizan secuencias de instrucciones diferentes cuando el código (finalmente) se compila en el código nativo por el compilador JIT. Un interruptor se implementa mediante una secuencia de instrucciones nativas que realizan una rama indirecta. (La secuencia normalmente carga una dirección de una tabla y luego se bifurca a esa dirección). Se implementa un if/else 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, basada en el análisis de las instrucciones del código nativo generado y/o la evaluación comparativa. (O posiblemente no. Para estar absolutamente seguro, necesitaría preguntar al autor (es) de esa regla PMD cómo derivaron ese número.)
¿Cómo definen la eficiencia?
Tiempo empleado para ejecutar las instrucciones.
Yo personalmente tengo un problema con esta regla ... o más precisamente con el mensaje. Creo que debería decir que una declaración if/else
es más simple y más legible que un interruptor con 2 casos. El problema de la eficiencia es secundario, y probablemente irrelevante.
¿Qué es PMD? ? ? – jmort253
PMD escanea el código fuente de Java y busca posibles problemas como posibles errores, código muerto, código subóptimo, expresiones complicadas y código duplicado. (Desplácese sobre las etiquetas) – Chords
También debe escanearse para ver la gramática. "Menos" debería ser "menos". :) – yshavit