A menudo encuentro que cuando depuro un programa es conveniente (aunque podría decirse que es una mala práctica) insertar una declaración de retorno dentro de un bloque de código. Podría intentar algo como esto en Java ...
class Test {
public static void main(String args[]) {
System.out.println("hello world");
return;
System.out.println("i think this line might cause a problem");
}
}
por supuesto, esto produciría el error del compilador.
Test.java:7: declaración inalcanzable
Podría entender por qué una advertencia podría justificarse porque tener código sin usar es una mala práctica. Pero no entiendo por qué esto necesita generar un error.
¿Es esto solo Java tratando de ser una niñera, o hay una buena razón para convertirlo en un error del compilador?
Respuestas:
Porque el código inalcanzable no tiene sentido para el compilador. Si bien hacer que el código sea significativo para las personas es fundamental y más difícil que hacerlo significativo para un compilador, el compilador es el consumidor esencial de código. Los diseñadores de Java adoptan el punto de vista de que el código que no es significativo para el compilador es un error. Su postura es que si tiene algún código inalcanzable, ha cometido un error que debe corregirse.
Aquí hay una pregunta similar: Código inalcanzable: ¿error o advertencia?, en el que el autor dice "Personalmente creo que debería ser un error: si el programador escribe un fragmento de código, siempre debería ser con la intención de ejecutarlo en algún escenario". Obviamente, los diseñadores de lenguajes de Java están de acuerdo.
Si el código inalcanzable debería impedir la compilación es una cuestión sobre la que nunca habrá consenso. Pero es por eso que los diseñadores de Java lo hicieron.
Varias personas en los comentarios señalan que hay muchas clases de código inalcanzable que Java no impide la compilación. Si entiendo correctamente las consecuencias de Gödel, ningún compilador puede capturar todas las clases de código inalcanzable.
Las pruebas unitarias no pueden detectar todos los errores. No usamos esto como un argumento en contra de su valor. Del mismo modo, un compilador no puede detectar todo el código problemático, pero aún así es valioso para evitar la compilación de código incorrecto cuando puede.
Los diseñadores del lenguaje Java consideran que el código inalcanzable es un error. Por lo tanto, evitar que se compile cuando sea posible es razonable.
(Antes de votar en contra: la pregunta no es si Java debería tener o no un error de compilador de declaración inalcanzable. La pregunta es por qué Java tiene un error de compilador de declaración inalcanzable. No me rechace solo porque crea que Java tomó la decisión de diseño incorrecta).
fuente
return; System.out.println();
yif(true){ return; } System.out.println();
tienen el mismo comportamiento, pero uno es un error de compilación y el otro no. Entonces, cuando estoy depurando, y uso este método para "comentar" el código temporalmente, así es como lo hago. El problema de comentar el código es que tienes que encontrar el lugar apropiado para detener tu comentario, lo que puede llevar más tiempo que lanzarloreturn;
rápidamente.No hay una razón definitiva por la que no se deban permitir declaraciones inalcanzables; otros idiomas los permiten sin problemas. Para su necesidad específica, este es el truco habitual:
if (true) return;
Parece una tontería, cualquiera que lea el código adivinará que debe haber sido hecho deliberadamente, no un error descuidado de dejar inalcanzable el resto de declaraciones.
Java tiene un poco de soporte para "compilación condicional"
http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.21
fuente
if (true) return;
no indica POR QUÉ se está saltando la lógica, mientras queif (BEHAVIOURDISABLED) return;
comunica la intención.Es Nanny. Siento que .Net lo hizo bien: genera una advertencia para el código inalcanzable, pero no un error. Es bueno estar advertido al respecto, pero no veo ninguna razón para evitar la compilación (especialmente durante las sesiones de depuración, donde es bueno lanzar un retorno para omitir algún código).
fuente
Acabo de notar esta pregunta y quería agregar mi $ .02 a esto.
En el caso de Java, esta no es realmente una opción. El error de "código inalcanzable" no proviene del hecho de que los desarrolladores de JVM pensaron en proteger a los desarrolladores de cualquier cosa, o estar más alerta, sino de los requisitos de la especificación de JVM.
Tanto el compilador de Java como la JVM utilizan lo que se denomina "mapas de pila", una información definida sobre todos los elementos de la pila, según lo asignado para el método actual. Se debe conocer el tipo de todas y cada una de las ranuras de la pila, de modo que una instrucción JVM no maltrate un elemento de un tipo por otro. Esto es muy importante para evitar que se utilice un valor numérico como puntero. Es posible, usando el ensamblaje de Java, intentar presionar / almacenar un número, pero luego abrir / cargar una referencia de objeto. Sin embargo, JVM rechazará este código durante la validación de la clase, es decir, cuando se crean mapas de pila y se prueba la coherencia.
Para verificar los mapas de la pila, la máquina virtual tiene que recorrer todas las rutas de código que existen en un método y asegurarse de que, independientemente de la ruta de código que se ejecute, los datos de la pila para cada instrucción concuerden con lo que ha empujado cualquier código anterior. / almacenado en la pila. Entonces, en el caso simple de:
Object a; if (something) { a = new Object(); } else { a = new String(); } System.out.println(a);
en la línea 3, JVM verificará que ambas ramas de 'if' solo se hayan almacenado en un (que es solo var # 0 local) algo que sea compatible con Object (ya que así es como el código de la línea 3 en adelante tratará la var # 0 local ).
Cuando el compilador llega a un código inalcanzable, no sabe muy bien qué estado podría estar la pila en ese punto, por lo que no puede verificar su estado. Ya no puede compilar el código en ese punto, ya que tampoco puede realizar un seguimiento de las variables locales, por lo que en lugar de dejar esta ambigüedad en el archivo de clase, produce un error fatal.
Por supuesto, una condición simple como
if (1<2)
lo engañará, pero no es realmente engañoso: le está dando una rama potencial que puede conducir al código, y al menos tanto el compilador como la VM pueden determinar cómo se pueden usar los elementos de la pila desde allí. en.PD: No sé qué hace .NET en este caso, pero creo que también fallará la compilación. Normalmente, esto no será un problema para ningún compilador de código de máquina (C, C ++, Obj-C, etc.)
fuente
{ [flowingstatement;]* }
=>flowingstatement
,{ [flowingstatement;]* stoppingstatement; }
=>stoppingstatement
,return
=>stoppingstatement
,if (condition) stoppingstatement; else stoppingstatement
=>stoppingstatement;
etc.?void blah() { try {return;} catch (RuntimeError ex) { } DoSomethingElse(); }
Java chirriaría que no había forma de que eltry
bloque pudiera salir realmente a través de una excepción, o pensaría que podría ocurrir cualquier tipo de excepción sin marcar dentro de cualquiertry
bloque?if (constantThatEqualsFive < 3) {doSomething;};
.Uno de los objetivos de los compiladores es descartar clases de errores. Algún código inalcanzable está allí por accidente, es bueno que javac descarte esa clase de error en el momento de la compilación.
Por cada regla que detecta código erróneo, alguien querrá que el compilador lo acepte porque sabe lo que está haciendo. Esa es la penalización de la verificación del compilador, y lograr el equilibrio correcto es uno de los puntos más engañosos del diseño del lenguaje. Incluso con la verificación más estricta, todavía hay una cantidad infinita de programas que se pueden escribir, por lo que las cosas no pueden ir tan mal.
fuente
Si bien creo que este error del compilador es bueno, hay una manera de solucionarlo. Utilice una condición que sepa que será cierta:
public void myMethod(){ someCodeHere(); if(1 < 2) return; // compiler isn't smart enough to complain about this moreCodeHere(); }
El compilador no es lo suficientemente inteligente como para quejarse de eso.
fuente
1<2
es cierto, y el resto del método no tiene que incluirse en el código de bytes. las reglas de las "declaraciones inalcanzables" deben ser claras, fijas e independientes de la inteligencia de los compiladores.Ciertamente, es bueno quejarse cuanto más estricto sea el compilador, mejor, en la medida en que le permita hacer lo que necesita. Por lo general, el pequeño precio a pagar es comentar el código, la ganancia es que cuando compila su código funciona. Un ejemplo general es Haskell sobre el cual la gente grita hasta que se dan cuenta de que su prueba / depuración es solo una prueba principal y una corta. Yo personalmente en Java casi no depuro mientras (de hecho, a propósito) no estoy atento.
fuente
Si la razón para permitir
if (aBooleanVariable) return; someMoreCode;
es permitir banderas, entonces el hecho de queif (true) return; someMoreCode;
no genere un error de tiempo de compilación parece una inconsistencia en la política de generar la excepción CodeNotReachable, ya que el compilador 'sabe' quetrue
no es una bandera (ni una variable).Otras dos formas que pueden ser interesantes, pero que no se aplican a desactivar parte del código de un método, así como
if (true) return
:Ahora, en lugar de decir,
if (true) return;
es posible que desee decirassert false
y agregar-ea OR -ea package OR -ea className
argumentos a jvm. El buen punto es que esto permite cierta granularidad y requiere agregar un parámetro adicional a la invocación de jvm, por lo que no es necesario configurar un indicador DEBUG en el código, sino mediante un argumento agregado en tiempo de ejecución, lo cual es útil cuando el objetivo no es el máquina de desarrollo y recompilar y transferir código de bytes lleva tiempo.También existe la
System.exit(0)
forma, pero esto podría ser una exageración, si lo pones en Java en una JSP, terminará el servidor.Aparte de que Java es por diseño un lenguaje 'niñera', prefiero usar algo nativo como C / C ++ para tener más control.
fuente
static final
variable que se establece en un bloque de inicialización estático a unastatic final
variable que se establece en su declaración no debería ser un cambio rotundo. Es completamente plausible que cuando una clase se escribe por primera vez, a veces no ha podido hacer algo (y no se sabe hasta el momento de la ejecución si podría hacerlo o no), pero las versiones posteriores de la clase podrían haberlo hecho. haz esa acción siempre. CambiarmyClass.canFoo
a una constante debería hacerif (myClass.canFoo) myClass.Foo(); else doSomethingElse();
más eficiente, no romperla.