2010-10-05 7 views
48

Hay 3 permutaciones de un try ... catch ... finally block en java.¿Realmente necesita el bloque 'finally'

  1. try ... catch
  2. try ... catch ... finally
  3. tratar ... finalmente

Una vez que se ejecuta el bloque finally, el control pasa a la línea siguiente después del bloque final. 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?

+3

Esta pregunta ha sido respondida antes de http://stackoverflow.com/questions/3354823/how-to-use-finally. Así que es un duplicado –

+1

[¡Se garantiza que se ejecute el código en un bloque finally! ¡Siempre! ¡Sin excepciones!] (Http://thedailywtf.com/Articles/My-Tales.aspx) – badp

+0

@Shervin, había leído ambas preguntas antes de marcar como duplicado –

Respuesta

42

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 mal con lo que está preguntando: "Si escribo todas las instrucciones después del bloque catch en lugar de escribirlas en el bloque finally entonces ¿habría algo mal?"

Si escribe todas las declaraciones después de que el bloque catch, lo que está dando a entender es que

1) Siempre detectar la excepción.

2) Siempre se continúe con el siguientes declaraciones después de detectar la excepción.

Esto implica que siempre se continuará la ejecución "normalmente" después de una excepción, que es generalmente algo que nunca de hecho quiero 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 un error para propagar 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 usted. 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.

"Deglución" de errores: atraparlos y seguir adelante 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á tantos bloques try ... finally como 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.

+2

recibí la misma respuesta de parte de mi gerente hace unos minutos –

+3

Su conclusión (1 y 2) es absolutamente incorrecta - No, esta pregunta no implica que él siempre detectará la excepción y/o siempre continuará con las instrucciones consiguientes. 1) Incluso si no detecta una excepción, aún continúa en las líneas consecuentes a menos que regrese de la función; 2) Si no regresas, no importa si continúas con try block o catch, SIEMPRE continuarás con las instrucciones consiguientes (si hay alguna), y eso es correcto, aquí no pasa nada. Hubiera contestado que se puede volver durante la prueba, pero finalmente se ejecutará. Esa es la diferencia. –

2

Sí, habría algo muy críticamente incorrecto.

Y es decir, su código solo se ejecutará si hay un error.

Las declaraciones dentro de finally siempre se ejecutan, independientemente de que se haya producido una excepción. Ese es el punto.

+2

Código de limpieza, por ejemplo, que desea que se ejecute si o no hay un error Eso pertenece a un bloque final. –

+0

Puede asegurarse de que se repita todo el tiempo agregando Lanzar nueva excepción(); como tu última línea en el bloque Try LOL – JumpingJezza

+2

, creo que entendiste mal las "todas las afirmaciones después del bloque catch", para mí suena como try {...; } captura { ....; } * todas las declaraciones *; – Maxem

38

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 java tutorial

El bloque finally siempre se ejecuta cuando el bloque try. Esto asegura que el bloque finally se ejecuta aunque ocurra una excepción inesperada. Pero finalmente es útil para algo más que el manejo de excepción de - permite que el programador evite tener el código de limpieza accidentalmente anulado por un return, continue o break. Poner código de limpieza en un bloque finally es siempre es una buena práctica, incluso cuando no se prevén excepciones .

+1

@articlestack también recuerda que finalmente no se llamará al bloque cuando System.exit(); se llama. –

+1

@Suresh S: buen punto, pero de todos modos en caso de System.exit ... nada importa ... (los recursos se liberan a nivel del sistema operativo) – helios

+0

@helios No se puede generalizar especialmente si el proceso está utilizando recursos de otro proceso. – reubenjohn

3

El bloque finally contiene líneas de código que se deben ejecutar 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 la t-c-f podría no ser ejecutado, 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).

+0

¿Qué pasa si ... intenta atrapar está ahí. ¿Pero estoy escribiendo declaraciones de reposo sin bloquear o finalmente bloquear? ¿cuál es la diferencia? –

1

finalmente bloque especialmente utilizado en el momento de la excepción de prevención. 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.

10

Si entiendo la pregunta, usted está preguntando ¿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 probablemente:

Foo f = new Foo(); 
f.bar(); 
Foo.baz(); 

La diferencia es que si new Foo() o f.bar() lanzan una excepción, elEl bloquese ejecutará en el primer caso, pero Foo.baz() no se ejecutará en los dos últimos casos: en su lugar, el control saltará el Foo.baz() mientras que la JVM busca un manejador de excepciones.


EDITAR

En respuesta a tu comentario, ¿qué pasa con:

Foo f = new Foo(); 
try { 
    f.bar(); 
} 
catch (Exception ex) 
{ 
    // ... 
} 

f.baz(); 

Tienes razón en que, suponiendo que el bloque de catch no volver a lanzar la excepción, o volver a partir del método para indicar que se produjo un error, se llama a 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 estaba haciendo sin saber que se produjo 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() convertir un String a un Double, y en caso de fallo que arroja un NumberFormatException, a continuación, el bloque de código después de try probablemente necesita saber que el String no se convierte realmente en un Double. Y, por lo tanto, en general, no querrá 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 relevante Double en Double.NaN, 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 que f.baz() está involucrado en algún tipo de limpieza.

+1

ni el primero ni el segundo fragmento de código no se compilarán. 'f' no está definido en' f.baz() '. (Llamar a 'baz()' sin 'f' sería suficiente) –

+0

Tienes razón. Gracias. Fijo. –

+1

Estaba diciendo que intente atrapar ambos bloques ae presentes. Ahora, ¿cuál es la necesidad de finalmente? Porque si se ha detectado un error y se ha tomado una acción específica, se ejecutará la siguiente declaración (ya sea finalmente {} o la declaración después de catch {}). –

1

Si su código nunca arroja una excepción, o si está consumiendo todas las excepciones que serán correctas. Eso no es lo que siempre sucede.Hace

0

Dos meses escribí un post para the reason behind 'finally' in a try/catch.

Consciente de que un enlace se interpone en el camino de la edición de una manera estilo wiki aquí.

Es una publicación autocontenida en la que simplemente copiarla no funcionaría ya que se perdería el comentario de seguimiento que también agrega valor.

28

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, las instrucciones 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 imprimirá:

Exception Happened 
Finally 

Esa es la razón más importante para la existencia de un bloque finally. 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.

+1

+1 completamente de acuerdo contigo –

Cuestiones relacionadas