2008-09-08 13 views
28

Sintaxis lado, ¿cuál es la diferencia entre¿Cuál es el punto del bloque finally?

try { 
} 
catch() { 
} 
finally { 
    x = 3; 
} 

y

try { 
} 
catch() { 
} 

x = 3; 

edición: en .NET 2.0?


por lo

try { 
    throw something maybe 
    x = 3 
} 
catch (...) { 
    x = 3 
} 

es equivalente conductualmente?

+0

Es posible que desee especificar un lenguaje de programación. El comportamiento variará según el idioma. –

+0

Para decidir la mejor respuesta, creo que debe aclarar si los bloques try/catch están vacíos o no. Como se indica en una de las respuestas, la semántica es la misma si los bloques de prueba/captura están vacíos, de lo contrario, las respuestas diferentes abordarán las diferencias semánticas. – Kasper

+0

Estoy de acuerdo con los comentarios anteriores, necesita aclarar el lenguaje real y revisar seriamente las respuestas dadas. Las respuestas upmodded son incorrectas o incompletas. –

Respuesta

32

Depende del idioma ya que puede haber algunas diferencias semánticas leves, pero la idea es que se ejecutará (casi) siempre, incluso si el código en el bloque try lanzó una excepción.

En el segundo ejemplo, si el código en el bloque catch retorna o sale, la x = 3 no se ejecutará. En el primero lo hará.

En la plataforma .NET, en algunos casos, no se producirá la ejecución del bloque finally: Excepciones de Seguridad, suspensiones hilo, ordenador apagado :), etc.

+2

Agregaría a la lista de métodos que impiden la ejecución del bloqueo final de la llamada * Environment.Exit *. – Luca

0

Para que pueda limpiar cualquier conexión abierta, etc. inicializada en el bloque try. Si abría una conexión y luego se producía una excepción, esa excepción no se cerraría correctamente. Este tipo de escenario es para lo que es el bloque finally.

10

En Java:

Por último siempre se obtiene la llamada, independientemente de si la excepción fue capturado correctamente en la captura(), o de hecho, si usted tiene un retén en absoluto.

37

Bueno, por un lado, si VUELVE dentro de su bloque de prueba, finalmente se ejecutará, pero el código enumerado debajo del bloque try-catch-finally no lo hará.

+0

No consideraría esta la respuesta real - más una declaración de hecho ... – Ian

+0

¡Con conexión! Yo diría que esto no es "la respuesta". –

+1

Tienes razón. Es una buena respuesta, pero supongo que no responde directamente a la pregunta planteada. Tal vez eso significa que debería haber hecho una mejor pregunta :) – Keshi

2

En el caso de que el intento y la captura estén vacíos, no hay diferencia. De lo contrario, puede estar seguro de que finalmente se ejecutará.

Si, por ejemplo, lanza una nueva excepción en su catchblock (rethrow), entonces la asignación solo se ejecutará, si está en el bloque finally.

Normalmente, finalmente se utiliza para limpiar después de usted (conexiones de base de datos, manejadores de archivos y los "me gusta").

Nunca se debe usar sentencias de control (retorno, break, continue) en un fin, ya que esto puede ser una pesadilla para el mantenimiento y por lo tanto se considera una mala práctica

1

El bloque finally siempre se llamará (bueno en realidad no always ...) incluso si se lanza una excepción o se llega a una declaración de devolución (aunque eso puede depender del idioma). Es una forma de limpiar que sabes que siempre se llamará.

+0

Siempre me ha encantado el artículo del wtf diario que ha vinculado, especialmente uno de los comentarios que sugiere que necesitamos un magicFairyFinally que esté garantizado para ejecutarse, ¡incluso sin poder! –

0

@Ed, es posible que esté pensando en algo así como un catch(...) que capta una excepción no especificada en C++.

Pero finally es un código que se ejecutará pase lo que pase en los bloques catch.

Microsoft tiene una página de ayuda en try-finally for C#

0

El bloque finally se encuentra en el mismo alcance que el try/catch, por lo que tendrá acceso a todas las variables definidas en el interior.

Imagine que tiene un manejador de archivos, esta es la diferencia en la forma en que se escribiría.

try 
{ 
    StreamReader stream = new StreamReader("foo.bar"); 
    stream.write("foo"); 
} 
catch(Exception e) { } // ignore for now 
finally 
{ 
    stream.close(); 
} 

comparación con

StreamReader stream = null; 
try 
{ 
    stream = new StreamReader("foo.bar"); 
    stream.write("foo"); 
} catch(Exception e) {} // ignore 

if (stream != null) 
    stream.close(); 

Recuerde sin embargo que nada en el interior, finalmente, no se garantiza la ejecución. Imagina que obtienes una señal de interrupción, Windows se bloquea o la energía se ha ido. Confiar finalmente en el código crítico de la empresa es malo.

+0

defina un idioma, ya que se implementa en su respuesta pero no se indica. – shsteimer

+0

Un stackoverflow también causará que un bloque finally no se ejecute. –

+1

Creo que el primer ejemplo de código es incorrecto (en C#): las variables declaradas en el bloque "try" son * no * en el alcance en los bloques catch o finally. Intenté esto en una aplicación C# de prueba y obtuve un error en tiempo de compilación en la referencia de bloque final: "El nombre 'stream' no existe en el contexto actual". –

0

Cualquier código en el finalmente se ejecuta en el incluso en caso de una excepción no controlada. Normalmente, el código finalmente se usa para limpiar declaraciones locales de código no administrado usando .dispose().

9

try catch finalmente es una construcción bastante importante. Puede estar seguro de que incluso si se lanza una excepción, se ejecutará el código en finally block. Es muy importante manejar los recursos externos para liberarlos. La recolección de basura no hará eso por usted. En la parte final no debe tener return declaraciones o lanzar excepciones. Es posible hacer eso, pero es una mala práctica y puede conducir a resultados impredecibles.

Si intenta este ejemplo:

try { 
    return 0; 
} finally { 
    return 2; 
} 

El resultado será 2 :)

Comparación con otros idiomas: Return From Finally

+0

Tenga en cuenta que Finally Block no siempre se ejecuta. Un stackoverflow (sin juego de palabras) hará que el bloque finally no se ejecute. –

+1

El resultado será 2 en Java. En C#, este código no se puede compilar. – thorn

0

Finalmente bloques que permiten, como desarrollador, para poner en orden después de ti mismo, independientemente de las acciones del código anterior en el bloque try {} que ha encontrado errores, y otros han señalado esto, se trata principalmente de liberar recursos: cerrar punteros/sockets/conjuntos de resultados, devolver conexiones a una piscina, etc.

@mats es muy correcto que siempre existe la posibilidad de fallos "duros" - finalmente se hace no deben incluir el código de misión crítica, que siempre debe hacerse de forma transaccional dentro del try {}

@mats nuevo - La verdadera belleza es que le permite lanzar excepciones de nuevo fuera de sus propios métodos, y todavía garantiza que poner en orden:

try 
{ 
StreamReader stream = new StreamReader("foo.bar"); 
mySendSomethingToStream(stream); 
} 
catch(noSomethingToSendException e) { 
    //Swallow this  
    logger.error(e.getMessage()); 
} 
catch(anotherTypeOfException e) { 
    //More serious, throw this one back 
    throw(e); 
} 
finally 
{ 
stream.close(); 
} 

por lo tanto, podemos coger muchos tipos de excepción, los procesan de forma diferente (el primero permite la ejecución para algo más allá del intento {}, el segundo regresa de manera efectiva), pero siempre limpia y ordenadamente claro.

4

Hay varias cosas que hacen que un bloque finally útil:

  1. Si regresa de los bloques try o de captura, el bloque finally está siendo ejecutado, justo antes de que el control se devuelve a la función de llamada
  2. Si se produce una excepción dentro del bloque catch, o si se produce un tipo de excepción no detectada en el bloque try, el código en el bloque finally se sigue ejecutando.

Esto hace que finalmente los bloques sean excelentes para cerrar las manijas o los sockets de archivo.

1

@iAn y @mats:

no me "derribar" nada en finally {} que fue "creada" en el try {} como una regla. Sería mejor extraer la creación del flujo fuera del intento {}. Si necesita manejar una excepción en la creación del flujo, esto podría hacerse en un ámbito mayor.

StreamReader stream = new StreamReader("foo.bar"); 
try { 
    mySendSomethingToStream(stream); 
} 
catch(noSomethingToSendException e) { 
    //Swallow this  
    logger.error(e.getMessage()); 
} 
catch(anotherTypeOfException e) { 
    //More serious, throw this one back 
    throw(e); 
} 
finally { 
    stream.close(); 
} 
+0

Solo una nota aquí la línea 'throw (e); // reescribe el seguimiento de la pila' es diferente de 'throw; // vuelve a lanzar la excepción original' – vitule

0

En Java, se usan para cualquier cosa que se desea ejecutar independientemente de si ha utilizado un "retorno", acaba de ejecutar a través del bloque try, o tenían una excepción atrapada.

Por ejemplo, cerrar una sesión de base de datos o una conexión JMS, o desasignar algunos recursos del sistema operativo.

Supongo que es similar en .NET?

Cuestiones relacionadas