occurred - java exceptions best practices
¿Realmente necesitas el bloque ''finalmente'' (9)
Hay 3 permutaciones de un try ... catch ... finally block en java.
- trata de atraparlo
- prueba ... atrapa ... finalmente
- prueba ... finalmente
Una vez que se ejecuta el bloque finally, el control pasa a la siguiente línea después del bloque finally. Si elimino el bloque finally y muevo todos sus enunciados a la línea después del bloque try ... catch, ¿tendría el mismo efecto que tenerlos en el bloque finally?
Creo que willcode es lo más cercano a expresar el punto clave aquí, y probablemente todos lo quieran decir pero no están claros.
El problema es que de hecho hay algo muy equivocado con lo que estás preguntando: "Si escribo todas las declaraciones después de capturar bloque en lugar de escribirlas en bloque finalmente, entonces ¿habría algo mal?"
Si escribe todas las declaraciones después del bloque catch, lo que está implicando es que
1) Siempre atrapará la excepción.
2) Siempre continuará con las siguientes declaraciones después de atrapar la excepción.
Esto implica que siempre continuará la ejecución "normalmente" después de una excepción, que generalmente es algo que en realidad nunca quiere hacer.
Las excepciones deberían ser solo eso, excepcionales. Si de hecho puede manejar una excepción, siempre es mejor escribir su código para considerar esas condiciones primero y no dar lugar a ninguna excepción. Si sigue este modelo, las excepciones son realmente excepcionales, condiciones que no podría anticipar o, como máximo, no solucionar. Realmente no anticipar es para lo que debes trabajar. Esto significa que en general no puede manejar excepciones verdaderas, lo que también significa que no debe continuar la ejecución, a menudo termina la aplicación.
Lo que normalmente se hace es permitir que un error propague una copia de seguridad de la pila de llamadas. Algunos dicen que esto se hace en la posibilidad de que alguien más arriba en la cadena pueda ser capaz de manejarlo. Yo diría que esencialmente nunca sucede, hay dos propósitos reales para hacer esto. Uno puede ser algo que el usuario puede arreglar, si hay uno. Por lo tanto, usted propaga la copia de seguridad de error hasta llegar a donde puede informarlo al usuario. O dos, un usuario no puede arreglarlo, pero desea obtener toda la pila de llamadas para la depuración. Luego lo atrapa en la parte superior para fallar con gracia.
El bloque finally ahora debería tener más significado para ti. Como todo el mundo dice que siempre se ejecuta. El uso más claro de un finalmente está realmente en un intento ... finalmente bloquear. Lo que estás diciendo ahora es si el código funciona bien, genial. Todavía tenemos que hacer un poco de limpieza y, finalmente, siempre se ejecuta, seguimos adelante. Pero si se produce una excepción, ahora realmente necesitamos ese bloqueo final porque es posible que aún tengamos que hacer una limpieza, pero ya no estamos detectando la excepción aquí, así que ya no vamos a seguir avanzando. El bloqueo final es esencial para garantizar la limpieza.
La idea de una excepción que siempre detiene la ejecución puede ser difícil de entender para alguien hasta que tenga una cierta cantidad de experiencia, pero esa es, de hecho, la manera de hacer siempre las cosas. Si ocurrió un error, o era tan pequeño que debiste haberlo contado para empezar, o de lo contrario hay cada vez más errores esperando que ocurra en el futuro.
Errores de "deglutir": atraparlos y continuar es lo peor que puede hacer porque su programa se vuelve impredecible y no puede encontrar y corregir errores.
El código bien escrito contendrá la mayor cantidad de intentos ... finalmente bloqueos que sean necesarios para garantizar que los recursos siempre se liberen sin importar el resultado. Pero el código bien escrito generalmente contiene solo un pequeño número de try ... catch blocks que existen principalmente para permitir que una aplicación falle tan elegantemente como sea posible, o diferir para el usuario, lo que significa al menos pasar un mensaje al usuario, etc. Pero generalmente no solo captas un error y sigues adelante.
El bloque finally contiene líneas de código que deben ejecutarse independientemente de si se ha capturado una excepción o no. Incluso si decide detener la ejecución del código en ese método. Entonces el código después de que el tcf no se pueda ejecutar, pero el código finalmente está "garantizado" (garantizado en el sentido de que no se bloquea de forma inmediata y no se puede manipular el error).
Hace dos meses escribí una publicación por la razón detrás de ''finalmente'' en una prueba / captura.
Consciente de que un enlace se interpone en el modo de editar en estilo wiki aquí.
Es una publicación independiente que simplemente copiarlo no funcionaría, ya que se perdería el comentario de seguimiento que también agrega valor.
Sé que esta es una pregunta muy antigua, pero me encontré hoy y estaba confundido por las respuestas dadas. Quiero decir, todos son correctos, pero todos responden en un nivel teórico o incluso filosófico cuando hay una respuesta práctica muy directa a esta pregunta.
Si pone un return, break, continue o cualquier otra palabra clave java que cambie la ejecución secuencial del código dentro del bloque catch (o incluso try block) , las sentencias dentro del bloque finally se seguirán ejecutando.
Por ejemplo:
public void myFunc() {
double p = 1.0D;
String str = "bla";
try{
p = Double.valueOf(str);
}
catch(Exception ex){
System.out.println("Exception Happened");
return; //return statement here!!!
}finally{
System.out.println("Finally");
}
System.out.println("After finally");
}
cuando se ejecuta este código se imprimirá:
Exception Happened
Finally
Esa es la razón más importante para la existencia de un bloque finalmente. La mayoría de las respuestas lo implican o lo mencionan al margen, pero ninguno de ellos pone énfasis en él. Creo que debido a que esta es una pregunta novata, una respuesta tan directa es muy importante.
Sí, habría algo muy críticamente incorrecto.
Y es decir, su código solo se ejecutará si hay un error .
Las sentencias dentro finally
siempre se ejecutan, independientemente de que se haya lanzado una excepción. Ese es el punto.
Se garantiza que un bloque finally se ejecutará incluso si se produce una excepción. Los usa para realizar la limpieza necesaria, como las secuencias de cierre. El código después del bloque finally podría no ser alcanzado.
Desde el tutorial java
El bloque finally siempre se ejecuta cuando sale el bloque try. Esto asegura que el bloque finally se ejecuta incluso si ocurre una excepción inesperada. Pero finalmente es útil para algo más que el manejo de excepciones: permite que el programador evite que el código de limpieza sea anulado accidentalmente por un retorno, continuación o interrupción. Poner el código de limpieza en un bloque finally es siempre una buena práctica, incluso cuando no se prevén excepciones.
Si entiendo la pregunta, te preguntas cuál es la diferencia entre:
try {
Foo f = new Foo();
f.bar();
}
finally
{
Foo.baz();
}
Y:
// This doesn''t actually compile because a try block needs a catch and/or finally block
try {
Foo f = new Foo();
f.bar();
}
Foo.baz();
O, más probable:
Foo f = new Foo();
f.bar();
Foo.baz();
La diferencia es que si el new Foo()
o f.bar()
lanzan una excepción, el bloque finally
se ejecutará en el primer caso, pero no se ejecutará Foo.baz()
en los dos últimos casos: en su lugar el control omitirá Foo.baz()
mientras la JVM busca un manejador de excepciones.
EDITAR
Respondiendo a tu comentario, ¿qué tal?
Foo f = new Foo();
try {
f.bar();
}
catch (Exception ex)
{
// ...
}
f.baz();
Tiene razón en que, suponiendo que el bloque catch
no vuelva a lanzar la excepción, o que regrese del método que indica que se produjo una falla, se f.baz()
independientemente de si hubo una excepción. Incluso en ese caso, sin embargo, el bloque finally
sirve como documentación que f.baz()
se utiliza para la limpieza.
Más importante aún, el hecho de que se lanzó una excepción generalmente es importante, por lo que es muy difícil escribir código que continúe haciendo lo que sea que esté haciendo sin saber que se lanzó una excepción. Hay ocasiones en que las excepciones indican cosas tontas que puede ignorar, y en ese caso debe tragar la excepción. Sin embargo, con más frecuencia, querrá señalar la falla, ya sea reiniciando la excepción (o lanzando una excepción diferente) o regresando del método con un código de error.
Por ejemplo, si se supone que f.bar()
debe convertir un String
en Double
, y en caso de error arroja una NumberFormatException
, entonces el código después del bloque try
probablemente necesite saber que el String
no se convirtió realmente en un Double
. Y, por lo tanto, en general no querrás continuar después del bloque catch
. En cambio, querrá señalar la falla. Esto se conoce como "abort on failure" (en comparación con "reanudar al fallar", que probablemente debería denominarse "confusión después de la falla con los dedos cruzados").
Excepto que, en casos especiales, es posible que te confundas. Por ejemplo, el bloque catch
podría establecer el Double
to Double.NaN
relevante, que está diseñado específicamente para propagar errores correctamente en expresiones matemáticas. Incluso en ese caso, el bloque finally
sirve como documentación de que f.baz()
está involucrado en algún tipo de limpieza.
Si su código nunca arroja una excepción, o está consumiendo todas las excepciones que serán correctas. Eso no es lo que siempre sucede.
finalmente bloquear especialmente utilizado en el momento de la prevención de excepciones. Si se produce algún error en el tiempo de ejecución, el programa puede dar lugar a la terminación. Entonces, en este momento, llamará finalmente al bloque antes de finalizar el programa. Por lo general, ''finalmente'' contiene declaraciones de cierre de conexión, operaciones de salvar y entrada de archivo, operaciones de cierre de salida.