Pregunta

Dejando a un lado la sintaxis, ¿cuál es la diferencia entre

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

y

try {
}
catch() {
}

x = 3;

editar:en .NET 2.0?


entonces

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

¿Es conductualmente equivalente?

¿Fue útil?

Solución

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

En el segundo ejemplo, si el código en el bloque catch regresa o se cierra, x = 3 no se ejecutará.En el primero lo será.

En la plataforma .NET, en algunos casos la ejecución del bloque finalmente no ocurrirá:Excepciones de seguridad, suspensiones de subprocesos, apagado de la computadora :), etc.

Otros consejos

Bueno, por un lado, si REGRESAS dentro de tu bloque try, finalmente se seguirá ejecutando, pero el código que aparece debajo del bloque try-catch-finally no.

En Java:

Finalmente siempre se llama, independientemente de si la excepción se detectó correctamente en catch() o, de hecho, si tiene alguna captura.

trata de atraparlo finalmente es una construcción bastante importante.Puede estar seguro de que incluso si se produce una excepción, se ejecutará el código del bloque finalmente.Es muy importante en el manejo de recursos externos liberarlos.La recolección de basura no hará eso por usted.En la parte final no deberías haberlo hecho. devolver declaraciones o lanzar excepciones.Es posible hacerlo, pero es una mala práctica y puede conducir a resultados impredecibles.

Si pruebas este ejemplo:

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

El resultado será 2 :)

Comparación con otros idiomas: Regresar desde finalmente

Hay varias cosas que hacen que un bloque finalmente sea útil:

  1. Si regresa de los bloques try o catch, el bloque finalmente aún se ejecuta, justo antes de que se devuelva el control a la función que llama.
  2. Si se produce una excepción dentro del bloque catch, o se produce un tipo de excepción no detectada en el bloque try, el código del bloque finalmente se sigue ejecutando.

Estos finalmente hacen que los bloques sean excelentes para cerrar identificadores de archivos o enchufes.

En el caso de que el try y el catch 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 bloque catch (volver a lanzar), la asignación solo se ejecutará si está en el bloque finalmente.

Normalmente, finalmente se usa para limpiar lo que usted deja (cerrar conexiones de base de datos, identificadores de archivos y similares).

Nunca debes usar declaraciones de control (return, break, continue) finalmente, ya que esto puede ser una pesadilla de mantenimiento y, por lo tanto, se considera una mala práctica.

El bloque finalmente siempre será llamado (bueno, en realidad no siempre ...) incluso si se lanza una excepción o se alcanza una declaración de devolución (aunque eso puede depender del idioma).Es una manera de limpiar que sabes que siempre será llamada.

@iAn y @mats:

Como regla general, no "derribaría" nada en finalmente {} que estuviera "configurado" dentro del intento {}.Sería mejor realizar la creación de la transmisión fuera del intento {}.Si necesita manejar una excepción en la transmisión, cree que esto podría hacerse en un alcance 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();  
}

Para que pueda limpiar cualquier conexión abierta, etc.inicializado en el bloque try.Si abrió una conexión y luego ocurrió una excepción, esa excepción no se cerrará correctamente.Este tipo de escenario es para lo que sirve el bloque final.

Se supone que el bloque finalmente se ejecuta independientemente de que haya detectado la excepción o no.Ver Ejemplo de prueba/captura/final

@Ed, podrías estar pensando en algo como un catch(...) que detecta una excepción no especificada en C++.

Pero finally es un código que se ejecutará sin importar lo que suceda en el catch bloques.

Microsoft tiene una página de ayuda en prueba finalmente para C#

El bloque finalmente está en el mismo alcance que try/catch, por lo que tendrá acceso a todas las variables definidas en su interior.

Imagina que tienes un controlador de archivos, esta es la diferencia en cómo se escribiría.

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

en comparación con

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

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

Sin embargo, recuerde que finalmente no se garantiza que todo lo que esté dentro funcione.Imagine que recibe una señal de cancelación, Windows falla o se corta la energía.Depender finalmente del código crítico para el negocio es malo.

Cualquier código finalmente se ejecuta 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().

Finalmente, los bloques le permiten, como desarrollador, ordenar lo que ensucia, independientemente de las acciones del código anterior en el bloque try{} que encontró errores, y si otros han señalado esto, cae principalmente bajo el paraguas de liberar recursos - cerrar punteros/sockets/conjuntos de resultados, devolver conexiones a un grupo, etc.

@mats tiene mucha razón en que siempre existe la posibilidad de que se produzcan fallos "difíciles"; finalmente, los bloques no deberían incluir código de misión crítica, lo que siempre debería realizarse de forma transaccional dentro del try{}

@mats nuevamente: la verdadera belleza es que le permite eliminar excepciones de sus propios métodos y aún así garantizar que ordene:

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 detectar muchos tipos de excepciones, procesarlas de manera diferente (la primera permite la ejecución de cualquier cosa más allá del try{}, la segunda efectivamente regresa), pero siempre limpiadas de manera clara y ordenada.

En Java, lo usa para cualquier cosa que desee ejecutar, independientemente de si usó un "retorno", simplemente ejecutó el bloque try o si se detectó una excepción.

Por ejemplo, cerrar una sesión de base de datos o una conexión JMS, o desasignar algún recurso del sistema operativo.

¿Supongo que es similar en .NET?

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