Pregunta

¿Alguien sabe por qué:

public void foo()
{
    System.out.println("Hello");
    return;
    System.out.println("World!");
}

sería reportado como un "error inalcanzable" en Eclipse, pero

public void foo()
{
    System.out.println("Hello");
    if(true) return;
    System.out.println("World!");
}

Sólo desencadena una advertencia "Dead código"?

La única explicación que se me ocurre es que el compilador de Java sólo banderas la primera, y que algunos análisis adicional en las cifras de Eclipse a cabo la segunda. Sin embargo, si ese es el caso, ¿por qué no el compilador de Java figura a cabo este caso en tiempo de compilación?

¿No el compilador de Java figura a cabo en tiempo de compilación que el código de bytes si (verdadero) no tiene ningún efecto, lo que se obtiene que es esencialmente idéntico? ¿En qué momento se aplica el análisis de código alcanzable?

Creo que una manera más general a pensar en esta pregunta es: "cuando se aplica el análisis de código accesible"? En la transformación del segundo fragmento de código Java para el código de bytes final, estoy seguro de que en algún momento se retira el "si (verdadero)" equivalente en tiempo de ejecución, y las representaciones de los dos programas a ser idénticas. No sería el compilador de Java a continuación, aplicar su análisis de código disponible de nuevo?

¿Fue útil?

Solución

La primera lo hace no de compilación (obtuvo un error), el segundo compila (que acaba de recibir un aviso). Esa es la diferencia.

En cuanto a por qué Eclipse detecta código muerto, bueno, eso es sólo la conveniencia de una herramienta de desarrollo integrado con un sistema incorporado en el compilador que se pueden afinarse más en comparación con el JDK para detectar este tipo de código.

Actualizar . JDK en realidad elimina el código muerto

public class Test {
    public void foo() {
        System.out.println("foo");
        if(true)return;
        System.out.println("foo");
    }
    public void bar() {
        System.out.println("bar");
        if(false)return;
        System.out.println("bar");
    }
}

javap -c dice:

public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   return

public void foo();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #3; //String foo
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/StrV
   8:   return

public void bar();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #5; //String bar
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  ldc             #5; //String bar
   13:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   16:  return

}

En cuanto a por qué (Sol) no da una advertencia acerca de eso, no tengo ni idea :) Al menos el compilador JDK tiene en realidad DCE (Código de Muertos Eliminación) incorporado.

Otros consejos

código inalcanzable es un error de acuerdo con la lenguaje Java Spec .

Para cita de la JLS:

  

La idea es que tiene que haber alguna posible ruta de ejecución desde el principio del constructor, método, inicializador de instancia o inicializador estático que contiene la instrucción a la propia declaración. El análisis tiene en cuenta la estructura de los estados. Excepto para el tratamiento especial de tiempo, hacer, y para los estados cuya expresión condición tiene el valor constante verdadera, los valores de las expresiones no se tienen en cuenta en el análisis de flujo.

Lo que esto significa, es que el bloque if no se tiene en cuenta, ya que si se va por uno de los caminos de la declaración if, se podría llegar a la declaración final de impresión. Si ha cambiado su código a ser:

public void foo() {
    System.out.println("Hello");
    if (true)
        return;
    else
        return;
    System.out.println("World!");
}

luego de repente sería no compila más, ya que no hay un camino a través del estado if que permitiría a la última línea para ser alcanzado.

Es decir, un compilador compatible con Java no se le permite compilar el primer fragmento de código. A más de presupuesto en los JLS:

  

A modo de ejemplo, los siguientes resultados declaración en un error de tiempo de compilación:

while (false) { x=3; }
  

porque la instrucción x = 3; no es accesible; pero el caso superficialmente similar:

if (false) { x=3; }
  

no da lugar a un error en tiempo de compilación. Un compilador de optimización puede darse cuenta de que la sentencia x = 3; nunca será ejecutado y puede optar por omitir el código para que la declaración del archivo de clase generada, pero la sentencia x = 3; No se considera como "inalcanzable" en el sentido técnico especificado aquí.

La segunda advertencia de que Eclipse da, sobre el código muerto, es una advertencia generados por el compilador, que no es "inalcanzable", de acuerdo con los JLS, pero en la práctica es. Se trata de una pelusa comprobación adicional estilo que ofrece Eclipse. Esto es totalmente opcional, y, mediante el uso de la configuración de Eclipse, se puede desactivar, o se convierte en un error de compilación en lugar de una advertencia.

Este segundo bloque es un "olor código", bloques if (false) normalmente se ponen en al código de desactivación para propósitos de depuración, que tiene dejó atrás es típicamente accidental, y por lo tanto la advertencia.

De hecho, ni siquiera Eclipse pruebas más avanzadas para determinar los posibles valores para una sentencia if para determinar si es o no es posible tomar dos caminos. Por ejemplo, Eclipse también se queja de código muerto en el método siguiente:

public void foo() {
    System.out.println("Hello");
    boolean bool = Random.nextBoolean();
    if (bool)
        return;
    if (bool || Random.nextBoolean())
      System.out.println("World!");
}

Se generará un código inalcanzable para la segunda sentencia if, ya que puede razonar que bool sólo debe ser false en este punto en el código. En un fragmento de código tan corto es obvio que si los dos estados están poniendo a prueba la misma cosa, sin embargo si hay 10-15 líneas de código en el medio que podría no ser tan obvio más.

Así que en resumen, la diferencia entre los dos:. Una de ellas es prohibido por las JLS, y uno no lo es, pero no se detecta por Eclipse como un servicio para el programador

Esto es para permitir una especie de condicionalmente compilación .
No es un error con if, pero la bandera compilador un error para while, do-while y for.
Esto está bien:

if (true) return;    // or false
System.out.println("doing something");

Estos son errores

while (true) {
}
System.out.println("unreachable");

while (false) {
    System.out.println("unreachable");
}

do {
} while (true);
System.out.println("unreachable");

for(;;) {
}
System.out.println("unreachable");

Se explica al final de JLS 14,21 : declaraciones inalcanzables :

  

La razón de esta diferencia de trato es permitir a los programadores definir las variables "bandera", tales como:

 static final boolean DEBUG = false;
     

y el código a continuación, escribir como:

   if (DEBUG) { x=3; }
     

La idea es que debe ser posible cambiar el valor de DEBUG de falso a verdadero o de verdadero a falso y luego compilar el código correctamente con ningún otro cambio en el texto del programa.

El if (true) es un poco más sutil que "inalcanzable"; debido a que return no modificable siempre va a hacer el siguiente código inalcanzable, pero cambiando la condición en el if podría hacer la siguiente declaración alcanzable.

Tener un condicional no significa que hay una condición de posibilidad podría cambiar. Hay casos en los que algo más complicado que un true está en los paréntesis, y no es evidente para el lector humano que el siguiente código es "amortiguado", pero los avisos del compilador, por lo que es capaz de advertir al respecto.

Eclipse se menciona aquí, y hace que las cosas parecen un poco más complicado para el usuario; pero en realidad por debajo de Eclipse es sólo una (muy sofisticado) compilador de Java que pasa a ofrecer una gran cantidad de interruptores para las advertencias etc., que Eclipse puede encender y apagar. En otras palabras, usted no consigue bastante la amplitud de las diferentes advertencias / errores de compilación de un javac recta, ni tiene medios convenientes para convertir todos ellos dentro o fuera. Pero es la misma cosa, sólo con más campanas y silbatos.

Creo que una manera de algunos, hasta que el código es inalcanzable es más probable un error, y los intentos de JLS para protegerse de este tipo de errores.

Permitir if (true) return; es una buena manera de evitar la limitación JLS si realmente quiere hacer esto a propósito. Si los JLS dejaron de esto, sería conseguir en el camino. Además, también debería dejar de:

 public static boolean DEBUG = true; //In some global class somewhere else


 ...

 if (DEBUG) return; //in a completely unrelated class.

 ...

Debido a la constante DEBUG está completamente en-forrado, y funcionalmente equivalente a sólo escribir un cierto en que si la condición. Desde una perspectiva de JLS esos dos casos son muy similares.

La diferencia está en la semántica entre el tiempo de ejecución y en tiempo de compilación. En el segundo ejemplo, las compilaciones de código a una rama if-else en el código de bytes, y el eclipse es simplemente lo suficientemente inteligente como para decir que la parte de los demás nunca será alcanzado en tiempo de ejecución. Eclipse sólo le advierte, porque todavía es código legal.

En el primer ejemplo, es un error porque el código es ilegal por parte de la definición de java. El compilador no le permiten crear código de bytes con los estados inalcanzables.

Me hizo algún intento en Eclipse y creo que hay 3 tipos de manipulación de código muerto de JDK: 1) no advertir, 2) advertir y 3) error.

En un típico "SI" código compilataion condicional, JDK detectar esto y aún no ha informe como código muerto. Para un código muerto que es causada por una bandera booleana constante, JDK detectar esto y repórtelo a nivel de advertencia. Para el código de salida que es causado por el flujo de control del programa, JDK lo detecta como error.

A continuación es mi intento:

    public class Setting {
        public static final boolean FianlDebugFlag = false;
    }


    class B {
    .....

    // no warn, it is typical "IF" conditional compilataion code
    if(Setting.FianlDebugFlag) 
        System.out.println("am i dead?");   
    if(false) 
        System.out.println("am i dead?");   


    // warn, as the dead code is caused by a constant boolean flag
    if(ret!=null && Setting.FianlDebugFlag) 
        System.out.println("am i dead?");   

    if(Setting.FinalDebug)                  
        return null;                                                            
    System.out.println("am i dea?");        

    // error, as the dead code is due to the program's control flow
    return null;
    System.out.println("am i dead");        
    }

Si desea ignorar el aviso de "alerta de código muerto en Java bajo Eclipse" hacer lo siguiente Eclipse dentro *:

  1. Haga clic en Window-Preferencias-java-compilador errores / advertencias
  2. Haga clic en "problemas de programación potenciales"
  3. Selecciona "Ignorar" del "Código Muerto por ejemplo, si (falso)"
  4. Haga clic en Aplicar
  5. Haga clic en Aceptar

Guardar y cerrar el IDE Eclipse Al volver a abrir eclipse, estas advertencias específicas ya no debería estar en la lista.

* Para esta solución ejemplo estoy usando Eclipse IDE para desarrolladores de Java - Versión: Mars.2 Release (4.5.2)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top