Pregunta

Mientras analizaba código heredado con FXCop, se me ocurrió si realmente es tan malo detectar un error de excepción general dentro de un bloque de prueba o si debería estar buscando una excepción específica.Pensamientos sobre una postal por favor.

¿Fue útil?

Solución

Obviamente ésta es una de esas preguntas donde la única respuesta real es "depende".

Lo principal depende de dónde está detectando la excepción.En general, las bibliotecas deberían ser más conservadoras a la hora de detectar excepciones, mientras que en el nivel superior de su programa (p. ej.en su método principal o en la parte superior del método de acción en un controlador, etc.) puede ser más liberal con lo que captura.

La razón de esto es que p.e.no desea detectar todas las excepciones en una biblioteca porque puede enmascarar problemas que no tienen nada que ver con su biblioteca, como "OutOfMemoryException", que realmente preferiría que apareciera para que el usuario pueda ser notificado, etc.Por otro lado, si está hablando de detectar excepciones dentro de su método main(), que detecta la excepción, la muestra y luego sale...bueno, probablemente sea seguro detectar casi cualquier excepción aquí.

La regla más importante para detectar todas las excepciones es que nunca debes tragarte todas las excepciones en silencio...p.ej.algo como esto en Java:

try { 
    something(); 
} catch (Exception ex) {}

o esto en Python:

try:
    something()
except:
    pass

Porque estos pueden ser algunos de los problemas más difíciles de rastrear.

Una buena regla general es que sólo debe detectar excepciones que pueda solucionar adecuadamente usted mismo.Si no puede manejar la excepción por completo, entonces debe dejar que se la pase a alguien que pueda hacerlo.

Otros consejos

A menos que esté registrando y limpiando el código en la interfaz de su aplicación, creo que es malo detectar todas las excepciones.

Mi regla básica es detectar todas las excepciones esperadas y cualquier otra cosa es un error.

Si captas todo y continúas, es como poner una tirita sobre la luz de advertencia en el tablero de tu auto.Ya no puedes verlo, pero eso no significa que todo esté bien.

¡Sí!(excepto en la "parte superior" de su aplicación)

Al detectar una excepción y permitir que continúe la ejecución del código, usted afirma que sabe cómo tratar, evitar o solucionar un problema en particular.Estás afirmando que esto es una situación recuperable.Detectar una excepción o SystemException significa que detectará problemas como errores de E/S, errores de red, errores de falta de memoria, errores de código faltante, desreferenciación de puntero nulo y similares.Es mentira decir que puedes lidiar con esto.

En una aplicación bien organizada, estos problemas irrecuperables deben manejarse en lo alto de la pila.

Además, a medida que el código evoluciona, no desea que su función detecte una nueva excepción que se agrega en el futuro a un método llamado.

En mi opinión, deberías detectar todas las excepciones. esperar, pero esta regla se aplica a cualquier cosa excepto a la lógica de su interfaz.A lo largo de la pila de llamadas, probablemente debería crear una forma de detectar todas las excepciones, registrar un poco/dar comentarios al usuario y, si es necesario y posible, cerrar correctamente.

No hay nada peor que una aplicación que falla y un seguimiento de pila poco amigable para el usuario se descarga en la pantalla.No solo brinda información (quizás no deseada) sobre su código, sino que también confunde al usuario final y, a veces, incluso lo asusta y lo aleja de una aplicación de la competencia.

Ha habido muchas discusiones filosóficas (más bien argumentos) sobre este tema.Personalmente, creo que lo peor que puedes hacer es tragarte las excepciones.El siguiente peor es permitir que una excepción suba a la superficie donde el usuario obtiene una pantalla desagradable llena de palabrería técnica.

Creo que el punto es doble.

En primer lugar, si no sabe qué excepción se ha producido, ¿cómo puede esperar recuperarse de ella?Si espera que un usuario escriba un nombre de archivo incorrecto, puede esperar una excepción FileNotFoundException y decirle al usuario que vuelva a intentarlo.Si ese mismo código generara una NullReferenceException y simplemente le dijera al usuario que lo intentara nuevamente, no sabría lo que había sucedido.

En segundo lugar, las pautas de FxCop se centran en el código de biblioteca/marco; no todas sus reglas están diseñadas para ser aplicables a sitios web EXE o ASP.Net.Por lo tanto, es bueno tener un controlador de excepciones global que registre todas las excepciones y salga de la aplicación correctamente.

El problema de detectar todas las excepciones es que puede detectar algunas que no espera o incluso algunas que debería. no ser contagioso.El hecho es que una excepción de cualquier tipo indica que algo salió mal y usted debe solucionarlo antes de continuar, de lo contrario puede terminar con problemas de integridad de datos y otros errores que no son tan fáciles de rastrear.

Para dar un ejemplo, en un proyecto implementé un tipo de excepción llamado CriticalException.Esto indica una condición de error que requiere la intervención de los desarrolladores y/o del personal administrativo, de lo contrario se facturará incorrectamente a los clientes o se podrían producir otros problemas de integridad de datos.También se puede utilizar en otros casos similares cuando simplemente registrar la excepción no es suficiente y es necesario enviar una alerta por correo electrónico.

Otro desarrollador que no entendía adecuadamente el concepto de excepciones luego incluyó un código que potencialmente podría generar esta excepción en un bloque try...catch genérico que descartó todas las excepciones.Afortunadamente, lo vi, pero podría haber resultado en problemas graves, especialmente porque el caso de esquina "muy poco común" que se suponía que detectaría resultó ser mucho más común de lo que esperaba.

Entonces, en general, detectar excepciones genéricas es malo a menos que esté 100% seguro de saberlo. exactamente qué tipos de excepciones se lanzarán y bajo qué circunstancias.En caso de duda, déjelos subir al controlador de excepciones de nivel superior.

Una regla similar aquí es nunca lanzar excepciones de tipo System.Exception.Es posible que usted (u otro desarrollador) desee detectar su excepción específica en una parte superior de la pila de llamadas mientras deja pasar a otros.

(Sin embargo, hay un punto a tener en cuenta.En .NET 2.0, si un subproceso encuentra excepciones no detectadas, descarga todo el dominio de su aplicación.Por lo tanto, debe envolver el cuerpo principal de un hilo en un bloque try...catch genérico y pasar cualquier excepción detectada allí a su código de manejo de excepciones global).

Bueno, no veo ninguna diferencia entre detectar una excepción general o una específica, excepto que cuando tienes múltiples bloques catch, puedes reaccionar de manera diferente dependiendo de cuál sea la excepción.

En conclusión, captarás ambos. IOException y NullPointerException con un genérico Exception, pero la forma en que debería reaccionar su programa probablemente sea diferente.

Me gustaría hacer de abogado del diablo para detectar una excepción, registrarla y volver a lanzarla.Esto puede ser necesario si, por ejemplo, está en algún lugar del código y ocurre una excepción inesperada, puede detectarla, registrar información de estado significativa que no estaría disponible en un seguimiento de pila simple y luego volver a enviarla a las capas superiores para tratar con.

Hay dos casos de uso completamente diferentes.El primero es en el que la mayoría de la gente está pensando: probar/capturar alguna operación que requiere una excepción marcada.Esto no debería ser un comodín de ninguna manera.

La segunda, sin embargo, es evitar que el programa se interrumpa cuando podría continuar.Estos casos son:

  • La parte superior de todos los hilos (¡de forma predeterminada, las excepciones desaparecerán sin dejar rastro!)
  • Dentro de un bucle de procesamiento principal del que esperas no salir nunca
  • Dentro de un bucle que procesa una lista de objetos donde una falla no debería detener a otras
  • Parte superior del hilo "principal": aquí puedes controlar un bloqueo, como volcar algunos datos a la salida estándar cuando te quedas sin memoria.
  • Si tiene un "Runner" que ejecuta código (por ejemplo, si alguien le agrega un oyente y usted llama al oyente), cuando ejecute el código debe detectar la excepción para registrar el problema y permitirle continuar notificando a otros oyentes.

En estos casos, SIEMPRE desea detectar excepciones (quizás incluso arrojables a veces) para detectar errores de programación/inesperados, registrarlos y continuar.

Creo que una buena pauta es detectar solo excepciones específicas dentro de un marco (para que la aplicación host pueda manejar casos extremos como el llenado del disco, etc.), pero no veo por qué no deberíamos poder detectar todas. excepciones de nuestro código de aplicación.Sencillamente, hay ocasiones en las que no quieres que la aplicación falle, sin importar lo que pueda salir mal.

La mayoría de las veces no es necesario detectar una excepción general.Por supuesto, hay situaciones en las que no tienes otra opción, pero en este caso creo que es mejor comprobar por qué necesitas detectarlo.Quizás haya algo mal en tu diseño.

Siento una excepción general como sostener un cartucho de dinamita dentro de un edificio en llamas y apagar la espoleta.Ayuda por un tiempo, pero la dinamita explotará de todos modos después de un tiempo.

Por supuesto, puede haber situaciones en las que sea necesario detectar una excepción general, pero sólo con fines de depuración.Los errores y errores deben corregirse, no ocultarse.

Para mi clase IabManager, que usé con facturación dentro de la aplicación (del ejemplo de TrivialDrive en línea), noté que a veces tenía que lidiar con muchas excepciones.Llegó al punto en que era impredecible.

Me di cuenta de que, siempre y cuando dejara de intentar consumir un producto dentro de la aplicación después de que ocurriera una excepción, que es donde ocurrirían la mayoría de las excepciones (al consumir, en lugar de comprar), estaría seguro.

Acabo de cambiar todas las excepciones a una excepción general y ahora no tengo que preocuparme de que se produzcan otras excepciones aleatorias e impredecibles.

Antes:

    catch (final RemoteException exc)
    {
        exc.printStackTrace();
    }
    catch (final IntentSender.SendIntentException exc)
    {
        exc.printStackTrace();
    }
    catch (final IabHelper.IabAsyncInProgressException exc)
    {
        exc.printStackTrace();
    }
    catch (final NullPointerException exc)
    {
        exc.printStackTrace();
    }
    catch (final IllegalStateException exc)
    {
        exc.printStackTrace();
    }

Después:

    catch (final Exception exc)
    {
        exc.printStackTrace();
    }

Opinión impopular:No precisamente.

Detecte todos los errores de los que puede recuperarse de manera significativa.A veces son todos ellos.

En mi experiencia, importa más dónde la excepción proviene de qué excepción se lanza realmente.Si mantiene sus excepciones en espacios reducidos, normalmente no se tragará nada que de otro modo sería útil.La mayor parte de la información codificada en el tipo de error es información auxiliar, por lo que generalmente terminas detectando efectivamente todo de ellos de todos modos (pero ahora debe buscar los documentos API para obtener el conjunto total de posibles excepciones).

Tenga en cuenta que algunas excepciones deberían aparecer en la parte superior en casi todos los casos, como Python KeyboardInterrupt y SystemExit.Afortunadamente para Python, estos se mantienen en una rama separada de la jerarquía de excepciones, por lo que puedes dejar que surjan al capturarlos. Exception.Una jerarquía de excepciones bien diseñada hace que este tipo de cosas sea realmente sencilla.

El momento principal en el que detectar excepciones generales causará problemas graves es cuando se trata de recursos que necesitan ser limpiados (quizás en un finally cláusula), ya que un controlador general puede fácilmente pasar por alto ese tipo de cosas.Afortunadamente esto no es realmente un problema para los idiomas con defer, construcciones como las de Python with, o RAII en C++ y Rust.

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