2010-01-11 16 views
15

Lógicamente, if(!foo) y if(foo == false) son equivalentes. ¿Cómo están representados en Java? ¿Hay alguna diferencia entre los dos después de la compilación, ya sea en el bytecode o en el rendimiento? No pude encontrar una respuesta en el JLS, y la búsqueda arrojó muchos resultados sobre el comportamiento = = = = typos y ==/igual() comportamiento. (En este caso, los símbolos obstaculizaron mi búsqueda, para futuros buscadores, operador de negación, es igual a falso, igual a falso, no condición).¿Cuál es la diferencia de rendimiento, si existe, entre if (! Foo) y if (foo == false) en Java?

Para evitar el debate de CW: esta pregunta NO es preguntando qué variante prefieren las personas o cuál se considera mejor estilo. Estoy interesado en las diferencias en la implementación del idioma, por lo que hay una respuesta correcta. Relacionados, pero no del todo-a-víctima: Difference between while (x = false) and while (!x) in Java?

EDIT:

El consenso general parece ser que un buen compilador debe optimizar estos a la misma cosa. Eso tiene sentido y es lo que sospechaba, pero, para hacer una pregunta aún MÁS académica, ¿es ese comportamiento en realidad obligatorio en cualquier lugar, o es "simplemente" lo razonable de hacer?

+0

Tenga en cuenta que esto es específico del compilador. – danben

+1

Hay dos preguntas aquí. El primero pregunta cómo se representa en Java (Bytecode). El segundo pregunta si hay diferencias en el rendimiento y el bytecode (supongo que el tamaño es el factor de preocupación aquí). –

+3

Cualquier compilador que no reconozca esa optimización no llegará muy lejos en el mercado;) –

Respuesta

44

El JLS especificaría el comportamiento requerido de las declaraciones. Sin embargo, cómo se implementan es un detalle de implementación del compilador y la JVM.

En la práctica, cualquier compilador digno de su sal debería emitir el mismo código de bytes para esas declaraciones. E incluso si no, la JVM los optimizaría adecuadamente.

Además, una mejor manera de responder a esto, es comprobar por sí mismo, utilizando javap:

  1. compilar una Test.java con el siguiente contenido:

    class Test { 
        void equals(boolean f) { 
         if (f == false) {} 
        } 
        void not(boolean f) { 
         if (!f) {} 
        } 
    } 
    $ javac Test.java 
    
  2. De-ensamblarlo:

    $ javap -c Test 
    Compiled from "Test.java" 
    class Test extends java.lang.Object{ 
    Test(); 
        Code: 
        0: aload_0 
        1: invokespecial #1; //Method java/lang/Object."<init>":()V 
        4: return 
    
    void equals(boolean); 
        Code: 
        0: iload_1 
        1: ifne 4 
        4: return 
    
    void not(boolean); 
        Code: 
        0: iload_1 
        1: ifne 4 
        4: return 
    
    } 
    

ACTUALIZACIÓN: Respondiendo a tu pregunta sobre la pregunta "académica". Como se mencionó anteriormente, el JLS solo se preocupa por el comportamiento. No hay nada en el estándar que realmente especifique cómo se debe implementar (bueno, JVMS brinda mucha orientación).

Mientras el compilador conserve el mismo comportamiento idéntico, el compilador es libre de implementarlo de manera diferente, con la posibilidad de un rendimiento en tiempo de ejecución diferente.

+0

¡Eso es lo que llamo buena voluntad! Felicidades por tu paciencia! –

+4

'javap -c' se desmonta, no se descompila. –

+1

Buena respuesta, gracias. Mencionar javap solo fue suficiente para un +1, nunca había oído hablar de él antes. – Pops

12

El compilador debe resolver el mismo código internamente, por lo que no hay diferencia.

+0

¿Qué le parece mostrarlo de la misma forma que notnoop? –

+5

¿Qué tal no votar una declaración libre sin referencia, prueba, etc. (incluso si es verdadero)? –

0

prueba decompiling the byte code y observa qué diferente se ve el código. Supongo que la compilación los resolvería de manera casi idéntica y cualquier pequeña diferencia resultaría en una diferencia de rendimiento insignificante.

+1

o incluso echar un vistazo al propio código de bytes http://stackoverflow.com/questions/800916/should-i-look-at-the-bytecode-that-is-produce-by-a-java-compiler – gingerbreadboy

0

bien, una respuesta más completa:

estaría muy sorprendido si cualquier compilador genera código de bytes diferente para estas variaciones. Para cualquiera que esté interesado, debería ser fácil verificar usando un desensamblador.

Dado que ambas expresiones (muy probablemente) se compilan en el mismo bytecode, no espero diferencia en el tamaño o el rendimiento.

0

El JLS dice que

la expresión en un if se evalúa bloque, entonces el resultado de esa expresión se compara con cierto

En tanto el no caso y la comparación de casos de objetos, una expresión necesita ser evaluada y luego comparada con verdadera. Si estaba comprobando un valor en lugar de realizar un operador en él, puede haber un beneficio de rendimiento teórico ya que la evaluación de la expresión se convierte en una opción negativa.

Pero en este caso, esperaría que el JIT produjera el mismo bytecode para ambas expresiones.

0

No debe haber diferencia en el bytecode generado para esos dos resultados y si lo hizo a menos que esté creando código para un dispositivo con recursos muy limitados (en cuyo caso no debería escribir en Java) la diferencia sería insignificante y usted debe decidir cuál de las dos formas de escribir este código es una solución más obvia.

0

Pensando en micro-optimizaciones se encuentra en casi todos los casos una pérdida de tiempo y conduce a pensar en formas equivocadas ...

+0

See mi comentario en el hilo de la pregunta. – Pops

0

me hizo una pregunta similar con respecto a C++/VS2008.

Would VS2008 c++ compiler optimize the following if statement?

Para evitar errores tipográficos vs = == en C++, que tendería a escribir

if (NULL == ptr) { ... } 
if (false == boo) { ... } 
if (20 == num) { ... } 

etc.

Esta cifra es ligeramente menos legible hasta que se acostumbre a ella.

Cuestiones relacionadas