2008-10-08 16 views
28

Tengo entendido que la sabiduría común dice que solo use excepciones para condiciones realmente excepcionales (De hecho, he visto esa declaración aquí en SO varias veces).¿Las excepciones son realmente para errores excepcionales?

Sin embargo, Krzysztof Cwalina dice:

Uno de los principales conceptos erróneos acerca de las excepciones es que son para la realidad es que son para la comunicación de las condiciones de error “condiciones excepcionales.”. Desde una perspectiva de diseño del marco, no existe una "condición excepcional". Si una condición es excepcional o no depende del contexto de uso, pero las bibliotecas reutilizables raramente saben cómo se usarán. Por ejemplo, OutOfMemoryException podría ser excepcional para una aplicación de entrada de datos simple; no es tan excepcional para aplicaciones que hacen su propia gestión de memoria (por ejemplo, servidor SQL). En otras palabras, la condición excepcional de un hombre es la condición crónica de otro hombre.

A continuación, también se llega a decir que las excepciones deben ser utilizados para:

  • errores de uso
  • errores de programa
  • fallos del sistema

teniendo en cuenta Krzysztof Cwalina es el PM del equipo de CLR en MS. Pregunto: ¿Qué piensas de su declaración?

Respuesta

21

Esto suena demasiado simplista, pero creo que tiene sentido simplemente usar excepciones donde sean apropiadas. En idiomas como Java y Python, las excepciones son muy comunes, especialmente en ciertas situaciones. Las excepciones son apropiadas para el tipo de error que desea crear a través de una ruta de código y obligar al desarrollador a atrapar explícitamente. En mi propia codificación, considero el momento adecuado para agregar una excepción cuando el error no puede ignorarse, o simplemente es más elegante lanzar una excepción en lugar de devolver un valor de error a una llamada de función, etc.

Algunos de los lugares más apropiados para las excepciones que se me ocurre de improviso:

  • NotImplementedException - de manera muy apropiada de designar que un método o función particular no está disponible, en lugar de simplemente volver sin hacer nada .
  • OutOfMemory excepciones - es difícil imaginar una mejor manera de manejar esta tipo de error, ya que representa una asignación de memoria o en todo el sistema operativo en todo el proceso de fracaso. Esto es esencial para tratar, por supuesto!
  • NullPointerException - Acceso a una variable nula es un error programador, y la OMI este es otro buen lugar para forzar un error de burbujas a la superficie
  • ArrayIndexException - En un lenguaje que no perdona como C, desbordamientos de búfer son desastrosos idiomas más agradables pueden devolver un valor nulo de algún tipo, o en algunas implementaciones, incluso envolver alrededor de la matriz. En mi opinión, lanzar una excepción es una respuesta mucho más elegante.

Esto no es de ninguna manera una lista completa, pero con suerte ilustra el punto. Use excepciones donde sean elegantes y lógicas. Como siempre con la programación, la herramienta correcta para el trabajo correcto es un buen consejo. No tiene sentido volverse loco por la locura en vano, pero tampoco es prudente ignorar por completo una herramienta potente y elegante a tu disposición.

+1

+1, me gusta implementar excepciones en mi propio código, para marcar elementos que requieren trabajo (es decir: No disponible), o para obtener informes de errores más detallados de errores específicos (es decir, operaciones de archivos de E/S). Los dejo burbujear hasta cierto nivel y luego enviarlos por correo electrónico a mí mismo. ¡Bueno para probar! –

+0

De acuerdo, la comunicación de error arrojando excepciones tiene su lugar. – jpoh

11

Para las personas que escriben marcos, quizás sea interesante.

Para el resto de nosotros, es confuso (y posiblemente inútil). Para las aplicaciones normales, las excepciones deben reservarse como situaciones "excepcionales". Las excepciones interrumpen la presentación secuencial ordinaria de su programa.

Debe tener cuidado de no romper el proceso secuencial ordinario de arriba hacia abajo de su programa. El manejo de excepciones es, intencionadamente, difícil de leer. Por lo tanto, reserve excepciones para cosas que están fuera de los escenarios estándar.

Ejemplo: No use excepciones para validar la entrada del usuario. Las personas cometen errores de entrada todo el tiempo. Eso no es excepcional, es por eso que escribimos software. Para eso son las declaraciones.

Cuando su aplicación recibe una excepción de OutOfMemory, no tiene sentido atraparla. Eso es excepcional. La suposición de "ejecución secuencial" está fuera de la ventana. Su aplicación está condenada al fracaso, solo se cuelga y espera que su transacción RDBMS finalice antes de que falle.

+2

Hola, amigo, no quiero ser grosero, pero no respaldas tu declaración por ningún motivo. –

+0

Eso es correcto, para los marcos o el desarrollo del sistema, el manejo de excepciones es bastante diferente que para las aplicaciones. – OscarRyz

+0

@Esteban Araya: buen punto: omití mencionar que el texto secuencial de arriba a abajo es importante. –

1

Me he estado preguntando sobre esto yo mismo. ¿Qué queremos decir con "excepcional"? Tal vez no haya una definición estricta, pero ¿hay alguna regla de oro que podamos usar para decidir qué es excepcional en un contexto dado?

Por ejemplo, ¿sería justo decir que una condición "excepcional" es aquella que viola el contrato de una función?

0

KCwalina tiene un punto. Será bueno identificar casos en los que el código fallará (hasta un límite)

Estoy de acuerdo con S.Lott en que a veces validar es mejor que lanzar Excepciones. Dicho esto, OutOfMemory no es lo que se podría esperar en su aplicación (a menos que se está asignando una gran memoria & necesita memoria para seguir adelante).

Creo, que depende del dominio de la aplicación.

6

Como normalmente programo en Python, y en ese idioma las excepciones están en todas partes, para mí una excepción puede representar desde un error de sistema hasta una condición completamente legítima.

Por ejemplo, la forma "pitónica" de comprobar si una cadena contiene un número entero es probar int (theString) y ver si genera una excepción. ¿Es eso un "error excepcional"?

Nuevamente, en Python siempre se piensa que el bucle for actúa sobre un iterador, y un iterador debe lanzar una excepción 'StopIteration' cuando finaliza su trabajo (el bucle for capta esa excepción). ¿Es eso "excepcional" de alguna manera?

+0

Frecuentemente uso Java's Integer.parseInt (String var) de la misma manera. – slim

+2

+1 Vine aquí para decir "Depende del idioma. En Python ...." –

+2

Tenga en cuenta que en Python esto puede funcionar, pero en Java, C++, VB y C#, capturar una excepción es muy lento, entre 40 y 400 veces más lento que un enunciado if. Dependiendo de su aporte (¿espera un no número ocasional, o sucederá a menudo), esto puede o no ser un buen diseño. Lo cual es nuevamente la razón por la cual las excepciones deberían usarse cuando la situación esperada es justamente eso: excepcional en comparación con lo normal. – Abel

3

Creo que cuanto más cerca del suelo está usted son las excepciones menos apropiadas como un medio de comunicación de error convertirse. En una abstracción más alta, como en Java o .net, una excepción puede constituir una forma elegante de transmitir mensajes de error a las personas que llaman. Sin embargo, este no es el caso en C. Esta es también una decisión de diseño de framework versus api.

8

De hecho, es difícil saber qué es exactamente lo que interpreta una "condición excepcional" que justifica el uso de una excepción en un programa.

Una instancia que es muy útil para usar comunicando la causa de los errores. A medida que la cita de Krzysztof Cwalina menciona: “condiciones excepcionales”

Uno de los mayores errores sobre excepciones es que son para La realidad es que son para la comunicación condiciones de error.

Para dar un ejemplo concreto, digamos que tenemos un método getHeader(File f) que está leyendo alguna cabecera de un archivo y devuelve un objeto FileHeader.

Puede haber varios problemas que pueden surgir al intentar leer datos de un disco. Quizás el archivo especificado no existe, el archivo contiene datos que no se pueden leer, errores inesperados de acceso al disco, falta de memoria, etc. Tener múltiples medios de falla significa que debe haber múltiples formas de informar qué salió mal.

Si no se usaron excepciones, pero era necesario comunicar el tipo de error que ocurrió, con la firma del método actual, lo mejor que podemos hacer es devolver un null. Dado que obtener un null no es muy informativo, la mejor comunicación que obtenemos de ese resultado es que "ocurrió algún tipo de error, por lo que no pudimos continuar, lo siento". - No comunica la causa del error.

(O, alternativamente, que pueden tener constantes de clases de objetos FileHeader que indican condiciones FileNotFound y dichos códigos de error, emulando, pero que realmente apesta a tener un tipo booleano con TRUE, FALSE, FILE_NOT_FOUND.)

Si hubiéramos conseguido un FileNotFound o DeviceNotReady excepción (hipotética), al menos sabemos cuál fue la fuente del error, y si se trataba de una aplicación de usuario final, podríamos manejar el error de forma de resolver el problema.

El uso del mecanismo de excepción proporciona un medio de comunicación que no requiere un respaldo para usar códigos de error para la notificación de condiciones que no están dentro del flujo normal de ejecución.

Sin embargo, eso no significa que todo debe ser manejado por excepciones. Como ha señalado S.Lott:

No utilizar excepciones para validar el usuario de entrada, por ejemplo. La gente comete errores todo el tiempo. Para eso están if-statements.

Eso es algo que no se puede enfatizar lo suficiente. Uno de los peligros de no saber cuándo utilizar exactamente las excepciones es la tendencia a ser feliz por la excepción; usando excepciones donde la validación de entrada sería suficiente.

Realmente no tiene sentido definir y lanzar una excepción InvalidUserInput cuando todo lo que se requiere para tratar una situación así es notificar al usuario de lo que se espera como entrada.

Además, debe tenerse en cuenta que la entrada del usuario es espera que tenga una entrada defectuosa en algún momento. Es una medida defensiva para validar los datos de entrada antes de enviar las entradas del mundo exterior a las partes internas del programa.

Es un poco difícil decidir qué es excepcional y qué no.

1

Creo que hay un par de buenas razones por las que las excepciones se deben utilizar para detectar problemas inesperados.

En primer lugar, crean un objeto para encapsular la excepción, que por definición debe hacer que sea mucho más costoso que procesar un enunciado if simple. Como ejemplo de Java, debe llamar a File.exists() en lugar de esperar y manejar rutinariamente una excepción FileNotFoundException.

En segundo lugar, las excepciones que se detectan fuera del método actual (o tal vez incluso de clase) hacen que el código sea mucho más difícil de leer que si el manejo estuviera incluido en un método.

Habiendo dicho eso, yo personalmente amo excepciones. Le eximen de la necesidad de manejar explícitamente todos esos errores tipo "may-happen-but-probably-never-will", que hacen que escriba repetidamente print-an-error-and-abort-on-non-zero-return- manejo de código de cada llamada de método.

Mi conclusión es ... si razonablemente puede esperar que suceda, entonces es parte de su aplicación y debe codificarla. Cualquier otra cosa es una excepción.

+0

¿Debo también hacer llamadas a 'File.hasReadPermission()' y 'File.isNotCorrupt()' cada vez que quiero leer un archivo? – daniel1426

0

La declaración de Krzysztof Cwalina es un poco engañosa. La declaración original se refiere a "condiciones excepcionales", para mí es natural que yo sea el que defina lo que es excepcional o no. Sin embargo, creo que el mensaje pasó por OK, ya que creo que todos estamos hablando de excepciones de 'desarrollador'.

Las excepciones son excelentes para la comunicación, pero con un pequeño diseño jerárquico también son excelentes para cierta separación de preocupaciones, especialmente entre capas (DAO, Business, etc.). Por supuesto, esto solo es útil si trata estas excepciones de manera diferente.

Un buen ejemplo de jerarquía es la jerarquía de excepciones de acceso a datos de primavera.

3

Si practica "contar, no preguntar", entonces una excepción es la forma en que un programa dice "No puedo hacer eso". Es "excepcional" en el sentido de que dices "do X" y no puede hacer X. Una simple situación de manejo de errores. En algunos idiomas es bastante común trabajar de esta manera, en Java y C++ las personas tienen otras opiniones porque las excepciones se vuelven bastante costosas.

general: excepción sólo significa "no puedo"

Pragmático: ... si puede permitirse el lujo de trabajar de esa manera en su idioma.

Ciudadanía: ... y su equipo lo permite.

0

creo que tiene razón. Eche un vistazo al análisis de números en java. Ni siquiera puedes verificar la cadena de entrada antes de analizar. Te obligan a analizar y recuperar NFE si algo salió mal. ¿El fallo de análisis es algo excepcional? Creo que no.

0

Ciertamente creo que las excepciones deben usarse solo si tiene una condición excepcional.

El problema está en la definición de "excepcional". Aquí está el mío:

Una condición es excepcional si está fuera del comportamiento normal asumido de la parte del sistema que plantea la excepción.

Esto tiene algunas implicaciones:

  • excepcional depende de sus supuestos. Si una función asume que se pasan parámetros válidos, entonces lanzar una IllegalArgumentException está bien. Sin embargo, si el contrato de una función dice que corregirá los errores de entrada en la entrada de alguna manera, entonces este uso es "normal" y no debería arrojar una excepción en un error de entrada.
  • Excepcional depende de la estratificación del subsistema. Una función IO de red ciertamente podría generar una excepción si la red no está commentada, ya que supone una conexión válida. Sin embargo, se esperaría que un intermediario de mensajes basado en ESB manejara las conexiones descartadas, por lo que si usaba internamente una función IO de la red, tendría que detectar y manejar el error de manera apropiada. En caso de que no sea obvio, try/catch es efectivamente equivalente a un subsistema que dice "una condición que es excepcional para uno de mis componentes es realmente considerada normal por mí, así que debo manejarla".
0

El dicho de que las excepciones se deben usar para circunstancias excepcionales se usa en "Effective Java Second Edition": uno de los mejores libros de Java.

El problema es que esto se saca de contexto. Cuando el autor afirma que las excepciones deben ser excepcionales, acaba de mostrar un ejemplo de uso de excepciones para finalizar un ciclo while, una mala excepción. Para citar:

las excepciones son, como su nombre lo indica, a utilícese solo para condiciones excepcionales; nunca deben usarse para el flujo de control ordinario .

Por lo tanto, todo depende de su definición de "condición de excepción". Tomado fuera de contexto, puede dar a entender que rara vez se debe utilizar.

Usar excepciones en lugar de devolver códigos de error es bueno, aunque usarlas para implementar una técnica "inteligente" o "más rápida" no es bueno. Eso es generalmente lo que se entiende por "condición excepcional".

excepción comprobada: errores menores que no son errores y no deben detener la ejecución. ex. IO o análisis de archivos Excepción no verificada - programación de "error" que desobedece un contrato de método - ej. OutOfBoundsException. O un error que hace que la continuación de la ejecución sea una muy mala idea - ex IO o análisis de archivos de un archivo muy importante. Quizás un archivo de configuración.

0

Lo que se reduce a qué herramienta se necesita para hacer el trabajo.

Las excepciones son una herramienta muy poderosa. Antes de usarlos, pregúnteles si necesitan este poder y la complejidad que conlleva.

Las excepciones pueden parecer simples, porque usted sabe que cuando se golpea la línea con la excepción, todo se detiene. ¿Qué pasa desde aquí?

¿Se producirá una excepción no detectada?

¿La excepción será atrapada por el manejo de error global?

¿La excepción se manejará mediante un manejo de errores más anidado y detallado?

Tienes que saber todo en la pila para saber qué hará esa excepción. Esto viola el concepto de independencia. Ese método ahora depende del manejo de errores para hacer lo que usted espera.

Si tengo un método no me importa lo que está fuera de ese método. Solo me debería importar cuál es la entrada, cómo procesarla y cómo devolver la respuesta.

Cuando utiliza una excepción, básicamente está diciendo, no me importa lo que pase desde aquí, algo salió mal y no quiero que empeore, haga lo que sea necesario para mitigar el problema.

Ahora si te importa cómo manejar el error, tendrás que pensar un poco más y compilarlo en la interfaz del método, p. si intenta encontrar algún objeto, posiblemente devuelva el valor predeterminado de ese objeto si no se puede encontrar uno en lugar de arrojar alguna excepción como "Objeto no encontrado".

Cuando crea errores en la interfaz de métodos, la firma de este método no solo es más descriptiva de lo que puede hacer, sino que impone la responsabilidad de cómo manejar el error en la persona que llama del método. El método del que llama puede ser capaz de resolverlo o no, y de lo contrario informaría de nuevo en la cadena. Eventualmente llegarás al punto de entrada de la aplicación. Ahora sería apropiado emitir una excepción, ya que es mejor que comprenda cómo se manejarán las excepciones si trabaja con la interfaz pública de las aplicaciones.

Déjeme darle un ejemplo de mi manejo de errores para un servicio web.

Nivel 1. Manejo global de errores en global.asax: esa es la red de seguridad para evitar excepciones no detectadas. Esto nunca debería ser intencionalmente alcanzado.

Nivel 2. Método de servicio web - Envuelto en un try/catch para garantizar que siempre cumpla con su interfaz json.

Nivel 3. Métodos de trabajador: estos obtienen datos, lo procesan y lo devuelven sin formato al método del servicio web.

En los métodos de trabajador no es correcto lanzar una excepción. Sí, tengo el manejo de errores del método de servicio web anidado, pero ese método se puede usar en otros lugares donde esto puede no existir.

En cambio, si se usa un método de trabajador para obtener un registro y no se puede encontrar el registro, simplemente devuelve nulo. El método del servicio web verifica la respuesta y cuando lo encuentra nulo, sabe que no puede continuar. El método de servicio web sabe que tiene un manejo de error para devolver json, por lo que lanzar una excepción simplemente devolverá los detalles en términos de lo sucedido. Desde la perspectiva de un cliente, es genial que se haya empaquetado en json que se pueda analizar fácilmente.

Verá que cada pieza solo sabe lo que tiene que hacer y lo hace. Cuando lanza una excepción en la mezcla, secuestra el flujo de aplicaciones. Esto no solo lleva a un código difícil de seguir, sino que la respuesta al abuso de excepciones es el try/catch.Ahora es más probable que abuse de otra herramienta muy poderosa.

Demasiado a menudo veo un try/catch atrapando todo en el medio de una aplicación, porque el desarrollador tiene miedo de que el método que usan sea más complejo de lo que parece.

0

Aquí está la definición de excepción: una excepción es un evento, que ocurre durante la ejecución de un programa, que interrumpe el flujo normal de las instrucciones del programa.

Por lo tanto, para responder a su pregunta, no. Las excepciones son para eventos disruptivos, que pueden o no ser excepcional. Me encanta esta definición, es simple y funciona siempre, si se aceptan excepciones como yo. Por ejemplo, un usuario envía un un/pw incorrecto, o tiene un argumento ilegal/una entrada de usuario incorrecta. Lanzar una excepción aquí es la forma más directa de resolver estos problemas, que son perjudiciales, pero no excepcionales, ni siquiera imprevistos.

Probablemente deberían haberse llamado interrupciones, pero ese barco ha navegado.

Cuestiones relacionadas