exception - todas - ¿Cuándo lanzar una excepción?
todas las excepciones en java (30)
Tengo excepciones creadas para cada condición que mi aplicación no espera. UserNameNotValidException
, PasswordNotCorrectException
etc.
Sin embargo, me dijeron que no debía crear excepciones para esas condiciones. En mi UML, esas SON excepciones al flujo principal, entonces ¿por qué no debería ser una excepción?
¿Alguna orientación o buenas prácticas para crear excepciones?
Creo que solo deberías lanzar una excepción cuando no hay nada que puedas hacer para salir de tu estado actual. Por ejemplo, si está asignando memoria y no hay ninguna para asignar. En los casos que menciona, puede recuperarse claramente de esos estados y devolver un código de error a su interlocutor en consecuencia.
Verá muchos consejos, incluso en las respuestas a esta pregunta, de que debe emitir excepciones solo en circunstancias "excepcionales". Eso parece superficialmente razonable, pero es un consejo defectuoso, porque reemplaza una pregunta ("cuándo debo lanzar una excepción") con otra pregunta subjetiva ("qué es excepcional"). En su lugar, siga los consejos de Herb Sutter (para C ++, disponible en el artículo del Dr. Dobbs Cuándo y cómo usar excepciones , y también en su libro con Andrei Alexandrescu, Estándares de codificación de C ++ ): lance una excepción si, y solo si
- no se cumple una condición previa (lo que generalmente hace que uno de los siguientes sea imposible) o
- la alternativa no cumpliría con una post-condición o
- La alternativa dejaría de mantener un invariante.
¿Por qué es esto mejor? ¿No reemplaza la pregunta con varias preguntas sobre condiciones previas, condiciones posteriores e invariantes? Esto es mejor por varias razones relacionadas.
- Las condiciones previas, las condiciones posteriores y las invariantes son características de diseño de nuestro programa (su API interna), mientras que la decisión de
throw
es un detalle de la implementación. Nos obliga a tener en cuenta que debemos considerar el diseño y su implementación por separado, y nuestro trabajo al implementar un método es producir algo que satisfaga las limitaciones de diseño. - Nos obliga a pensar en términos de condiciones previas, postcondiciones e invariantes, que son las únicas suposiciones que los llamadores de nuestro método deberían hacer, y se expresan con precisión, permitiendo un acoplamiento flexible entre los componentes de nuestro programa.
- Ese acoplamiento suelto nos permite refactorizar la implementación, si es necesario.
- Las post-condiciones e invariantes son verificables; da como resultado un código que puede probarse fácilmente por unidad, ya que las condiciones posteriores son predicados que nuestro código de prueba de unidad puede verificar (hacer valer).
- Pensar en términos de condiciones posteriores produce naturalmente un diseño que tiene éxito como condición posterior , que es el estilo natural para el uso de excepciones. La ruta de ejecución normal ("feliz") de su programa se presenta de forma lineal, con todo el código de manejo de errores movido a las cláusulas
catch
.
En general, desea lanzar una excepción para cualquier cosa que pueda suceder en su aplicación que sea "Excepcional"
En su ejemplo, ambas excepciones parecen que las está llamando a través de una contraseña / validación de nombre de usuario. En ese caso, se puede argumentar que no es realmente excepcional que alguien escriba incorrectamente un nombre de usuario / contraseña.
Son "excepciones" al flujo principal de su UML pero son más "ramas" en el procesamiento.
Si intentara acceder a su archivo o base de datos passwd y no pudo, sería un caso excepcional y justificaría lanzar una excepción.
En primer lugar, si los usuarios de su API no están interesados en fallas específicas y específicas, entonces tener excepciones específicas para ellos no tiene ningún valor.
Dado que a menudo no es posible saber qué puede ser útil para sus usuarios, un mejor enfoque es tener las excepciones específicas, pero asegúrese de que se hereden de una clase común (por ejemplo, std :: exception o sus derivados en C ++). Eso le permite a su cliente detectar excepciones específicas si lo eligen, o la excepción más general si no les importa.
Estoy de acuerdo con japollock hasta allí: lance una aceptación cuando no esté seguro del resultado de una operación. Llamadas a API, acceso a sistemas de archivos, llamadas a bases de datos, etc. En cualquier momento, se está moviendo más allá de los "límites" de sus lenguajes de programación.
Me gustaría agregar, siéntase libre de lanzar una excepción estándar. A menos que vaya a hacer algo "diferente" (ignorar, enviar por correo electrónico, registrar, mostrar esa cosa de la ballena de Twitter, etc.), entonces no se moleste con las excepciones personalizadas.
La razón principal para evitar lanzar una excepción es que hay una gran cantidad de gastos generales relacionados con lanzar una excepción.
Una cosa que el artículo a continuación establece es que una excepción es para condiciones excepcionales y errores.
Un nombre de usuario incorrecto no es necesariamente un error de programa sino un error de usuario ...
Aquí hay un buen punto de partida para las excepciones dentro de .NET: http://msdn.microsoft.com/en-us/library/ms229030(VS.80).aspx
La regla de oro para lanzar excepciones es bastante simple. lo hace cuando su código ha entrado en un estado NO VÁLIDO INCREIBLE. Si los datos están comprometidos o no puede revertir el procesamiento que ocurrió hasta el momento, debe finalizarlo. de hecho, ¿qué más puedes hacer? su lógica de procesamiento eventualmente fallará en otro lugar. Si puede recuperarse de alguna manera, haga eso y no lance la excepción.
en su caso particular, si se vio obligado a hacer algo tonto, como aceptar el retiro de dinero y solo luego verificar el usuario / contraseña, debe terminar el proceso lanzando una excepción para notificar que algo malo ha ocurrido y evitar daños mayores.
La respuesta simple es, cuando una operación es imposible (debido a una aplicación O porque violaría la lógica de negocios). Si se invoca un método y es imposible hacer para qué se escribió el método, lanzar una Excepción. Un buen ejemplo es que los constructores siempre lanzan ArgumentExceptions si no se puede crear una instancia utilizando los parámetros proporcionados. Otro ejemplo es InvalidOperationException, que se lanza cuando no se puede realizar una operación debido al estado de otro miembro o miembros de la clase.
En su caso, si se invoca un método como Inicio de sesión (nombre de usuario, contraseña), si el nombre de usuario no es válido, es correcto lanzar una UserNameNotValidException o PasswordNotCorrectException si la contraseña es incorrecta. El usuario no puede iniciar sesión con los parámetros proporcionados (es decir, es imposible porque violaría la autenticación), así que lance una Excepción. Aunque podría tener sus dos excepciones heredadas de ArgumentException.
Dicho esto, si no desea lanzar una excepción porque un error de inicio de sesión puede ser muy común, una estrategia es crear un método que devuelva tipos que representen diferentes errores. Aquí hay un ejemplo:
{ // class
...
public LoginResult Login(string user, string password)
{
if (IsInvalidUser(user))
{
return new UserInvalidLoginResult(user);
}
else if (IsInvalidPassword(user, password))
{
return new PasswordInvalidLoginResult(user, password);
}
else
{
return new SuccessfulLoginResult();
}
}
...
}
public abstract class LoginResult
{
public readonly string Message;
protected LoginResult(string message)
{
this.Message = message;
}
}
public class SuccessfulLoginResult : LoginResult
{
public SucccessfulLogin(string user)
: base(string.Format("Login for user ''{0}'' was successful.", user))
{ }
}
public class UserInvalidLoginResult : LoginResult
{
public UserInvalidLoginResult(string user)
: base(string.Format("The username ''{0}'' is invalid.", user))
{ }
}
public class PasswordInvalidLoginResult : LoginResult
{
public PasswordInvalidLoginResult(string password, string user)
: base(string.Format("The password ''{0}'' for username ''{0}'' is invalid.", password, user))
{ }
}
A la mayoría de los desarrolladores se les enseña a evitar Excepciones debido a los gastos generales causados por lanzarlos. Es genial tener en cuenta los recursos, pero generalmente no a expensas del diseño de la aplicación. Esa es probablemente la razón por la que le dijeron que no lanzara sus dos Excepciones. Ya sea que se usen o no las Excepciones, generalmente se reduce a la frecuencia con que ocurrirá la Excepción. Si es un resultado bastante común o bastante esperado, esto es cuando la mayoría de los desarrolladores evitarán las Excepciones y, en su lugar, crearán otro método para indicar fallas, debido al supuesto consumo de recursos.
Este es un ejemplo de cómo evitar el uso de excepciones en un escenario como el que se acaba de describir, usando el patrón Try ():
public class ValidatedLogin
{
public readonly string User;
public readonly string Password;
public ValidatedLogin(string user, string password)
{
if (IsInvalidUser(user))
{
throw new UserInvalidException(user);
}
else if (IsInvalidPassword(user, password))
{
throw new PasswordInvalidException(password);
}
this.User = user;
this.Password = password;
}
public static bool TryCreate(string user, string password, out ValidatedLogin validatedLogin)
{
if (IsInvalidUser(user) ||
IsInvalidPassword(user, password))
{
return false;
}
validatedLogin = new ValidatedLogin(user, password);
return true;
}
}
La seguridad está combinada con su ejemplo: no debe decirle a un atacante que existe un nombre de usuario, pero la contraseña es incorrecta. Esa es información adicional que no necesitas compartir. Simplemente diga "el nombre de usuario o la contraseña son incorrectos".
Las clases de excepción son como las clases "normales". Usted crea una nueva clase cuando "es" un tipo diferente de objeto, con diferentes campos y diferentes operaciones.
Como regla general, debe probar el equilibrio entre el número de excepciones y la granularidad de las excepciones. Si su método arroja más de 4-5 excepciones diferentes, probablemente pueda combinar algunas de ellas en excepciones más "generales" (por ejemplo, en su caso "AuthenticationFailedException"), y usar el mensaje de excepción para detallar qué fue lo que salió mal. A menos que su código maneje cada uno de ellos de manera diferente, no necesita crear muchas clases de excepción. Y si lo hace, puede que simplemente devuelva una enumeración con el error que ocurrió. Es un poco más limpio de esta manera.
Las excepciones de lanzamiento hacen que la pila se desenrolle, lo que tiene algunos impactos en el rendimiento (los entornos modernos admitidos y mejorados han mejorado). Aún así, repetidamente lanzar y atrapar excepciones en una situación anidada sería una mala idea.
Probablemente más importante que eso, las excepciones son para condiciones excepcionales. No deben usarse para el flujo de control ordinario, ya que esto afectará la legibilidad de su código.
Las excepciones están destinadas a eventos que son comportamientos anormales, errores, fallas y demás. En su lugar, la lógica del programa debe manejar el comportamiento funcional, el error del usuario, etc. Dado que una cuenta o contraseña incorrecta es una parte esperada del flujo lógico en una rutina de inicio de sesión, debe poder manejar esas situaciones sin excepciones.
Las excepciones son un efecto un tanto costoso, si, por ejemplo, tiene un usuario que proporciona una contraseña no válida, por lo general es una mejor idea devolver un indicador de falla, o algún otro indicador de que no es válido.
Esto se debe a la forma en que se manejan las excepciones, la verdadera entrada incorrecta y los elementos únicos de detención críticos deben ser excepciones, pero no información de inicio de sesión fallida.
Mi guía personal es: se lanza una excepción cuando se encuentra que una suposición fundamental del bloque de código actual es falsa.
Ejemplo 1: digamos que tengo una función que se supone que examina una clase arbitraria y devuelve true si esa clase se hereda de la Lista <>. Esta función hace la pregunta: "¿Es este objeto un descendiente de la Lista?" Esta función nunca debe lanzar una excepción, ya que no hay áreas grises en su operación; cada clase individual puede o no heredar de la Lista <>, por lo que la respuesta es siempre "sí" o "no".
Ejemplo 2: digamos que tengo otra función que examina una Lista <> y devuelve verdadero si su longitud es mayor que 50, y falso si la longitud es menor. Esta función hace la pregunta: "¿Tiene esta lista más de 50 elementos?" Pero esta pregunta hace una suposición: asume que el objeto que se le da es una lista. Si le doy un NULO, entonces esa suposición es falsa. En ese caso, si la función devuelve verdadero o falso, entonces está rompiendo sus propias reglas. La función no puede devolver nada y afirma que respondió a la pregunta correctamente. Así que no vuelve, lanza una excepción.
Esto es comparable a la "pregunta cargada" de la falacia lógica. Cada función hace una pregunta. Si la entrada que se le da hace que la pregunta sea una falacia, entonces arroje una excepción. Esta línea es más difícil de dibujar con funciones que se vuelven nulas, pero la línea de fondo es: si se violan las suposiciones de la función sobre sus entradas, debería lanzar una excepción en lugar de regresar normalmente.
El otro lado de esta ecuación es: si encuentra que sus funciones generan excepciones con frecuencia, entonces probablemente necesite refinar sus suposiciones.
Mis pequeños lineamientos están fuertemente influenciados por el gran libro "Código completo":
- Utilice excepciones para notificar sobre cosas que no deben ignorarse.
- No use excepciones si el error puede ser manejado localmente
- Asegúrese de que las excepciones se encuentren en el mismo nivel de abstracción que el resto de su rutina.
- Las excepciones deben reservarse para lo que es verdaderamente excepcional .
NO es una excepción si el nombre de usuario no es válido o la contraseña no es correcta. Esas son cosas que debe esperar en el flujo normal de operación. Las excepciones son cosas que no forman parte del funcionamiento normal del programa y son bastante raras.
EDITAR: no me gusta usar excepciones porque no se puede saber si un método produce una excepción con solo mirar la llamada. Es por eso que las excepciones solo deben usarse si no puede manejar la situación de una manera decente (piense que "sin memoria" o "la computadora está en llamas").
Otros proponen que no se deben usar excepciones porque el inicio de sesión incorrecto se espera en un flujo normal si el usuario se equivoca. No estoy de acuerdo y no entiendo el razonamiento. Compárelo con abrir un archivo ... si el archivo no existe o no está disponible por algún motivo, el marco lanzará una excepción. El uso de la lógica anterior fue un error de Microsoft. Deberían haber devuelto un código de error. Lo mismo para análisis, webrequests, etc., etc.
No considero que un inicio de sesión incorrecto forme parte de un flujo normal, es excepcional. Normalmente, el usuario escribe la contraseña correcta y el archivo existe. Los casos excepcionales son excepcionales y está perfectamente bien usar excepciones para ellos. Complicar su código al propagar los valores de retorno a través de n niveles en la pila es una pérdida de energía y resultará en un código desordenado. Haz lo más simple que pueda funcionar. No optimice prematuramente usando códigos de error, las cosas excepcionales por definición rara vez ocurren, y las excepciones no cuestan nada a menos que las arroje.
Porque son cosas que sucederán normalmente. Las excepciones no son mecanismos de control de flujo. Los usuarios a menudo obtienen contraseñas incorrectas, no es un caso excepcional. Las excepciones deben ser una cosa realmente rara, UserHasDiedAtKeyboard
tipo situaciones.
Si el código se ejecuta dentro de un bucle que probablemente cause una excepción una y otra vez, lanzar excepciones no es bueno, ya que son bastante lentos para una N grande. Pero no hay nada de malo en lanzar excepciones personalizadas si el rendimiento no es bueno. un problema. Solo asegúrese de tener una excepción base que todos ellos heredan, llamada BaseException o algo así. BaseException hereda System.Exception, pero todas sus excepciones heredan BaseException. Incluso puede tener un árbol de tipos de Excepción para agrupar tipos similares, pero esto puede o no ser excesivo.
Entonces, la respuesta corta es que si no causa una penalización de rendimiento significativa (que no debería hacerlo a menos que esté lanzando muchas excepciones), entonces siga adelante.
Tengo problemas filosóficos con el uso de excepciones. Básicamente, usted espera que ocurra un escenario específico, pero en lugar de manejarlo de manera explícita, está presionando el problema para que sea manejado "en otra parte". Y donde ese "en otro lugar" puede ser la conjetura de cualquiera.
Tengo tres tipos de condiciones que capturo.
La entrada incorrecta o faltante no debe ser una excepción. Utilice js del lado del cliente y expresiones regulares del lado del servidor para detectar, establecer atributos y reenviar a la misma página con mensajes.
La AppException. Esta suele ser una excepción que usted detecta y lanza en su código. En otras palabras, estos son los que usted espera (el archivo no existe). Regístrelo, configure el mensaje y vuelva a la página de error general. Esta página usualmente tiene un poco de información sobre lo que pasó.
La excepción inesperada. Estos son los que no conoces. Regístrelo con detalles y reenvíelos a una página de error general.
Espero que esto ayude
Una regla de oro es usar excepciones en el caso de algo que normalmente no podría predecir. Algunos ejemplos son la conectividad de la base de datos, el archivo faltante en el disco, etc. Para los escenarios que puede predecir, es decir, los usuarios que intentan iniciar sesión con una contraseña incorrecta deben usar funciones que devuelven valores booleanos y saber cómo manejar la situación con elegancia. No desea terminar abruptamente la ejecución lanzando una excepción solo porque alguien haya escrito su contraseña por error.
Yo diría que generalmente todo fundamentalismo lleva al infierno.
Ciertamente, no querrá terminar con un flujo impulsado por excepciones, pero evitar las excepciones es también una mala idea. Tienes que encontrar un equilibrio entre ambos enfoques. Lo que no haría es crear un tipo de excepción para cada situación excepcional. Eso no es productivo.
Lo que generalmente prefiero es crear dos tipos básicos de excepciones que se utilizan en todo el sistema: LogicalException y TechnicalException . Estos pueden distinguirse más por los subtipos si es necesario, pero generalmente no es necesario.
La excepción técnica denota la excepción realmente inesperada, como la caída del servidor de la base de datos, la conexión al servicio web arrojó la excepción IOException, etc.
Por otro lado, las excepciones lógicas se utilizan para propagar la situación errónea menos grave a las capas superiores (generalmente algún resultado de validación).
Tenga en cuenta que incluso la excepción lógica no está pensada para usarse de manera regular para controlar el flujo del programa, sino para resaltar la situación en la que el flujo realmente debería terminar. Cuando se usa en Java, ambos tipos de excepción son subclases de RuntimeException y el manejo de errores está altamente orientado a aspectos.
Por lo tanto, en el ejemplo de inicio de sesión puede ser conveniente crear algo como la excepción AuthenticationException y distinguir las situaciones concretas por los valores de enumeración como UsernameNotExisting , PasswordMismatch , etc. Entonces, no tendrá una gran jerarquía de excepciones y podrá mantener los bloques catch en un nivel de mantenimiento. . También puede emplear fácilmente algún mecanismo genérico de manejo de excepciones, ya que tiene las excepciones categorizadas y sabe muy bien qué propagar hasta el usuario y cómo.
Nuestro uso típico es lanzar la excepción LogicalException durante la llamada al servicio web cuando la entrada del usuario no es válida. La Excepción se clasifica en el detalle de SOAPFault y luego se vuelve a anular la excepción en el cliente, lo que da como resultado que se muestre el error de validación en un determinado campo de entrada de página web, ya que la excepción tiene la asignación adecuada a ese campo.
Esta no es ciertamente la única situación: no es necesario utilizar el servicio web para lanzar la excepción. Usted es libre de hacerlo en cualquier situación excepcional (como en el caso de que necesite fallar), todo queda a su criterio.
Yo diría que no hay reglas duras y rápidas sobre cuándo usar excepciones. Sin embargo, hay buenas razones para usarlos o no:
Razones para usar excepciones:
- El flujo de código para el caso común es más claro.
- Puede devolver información de error compleja como un objeto (aunque esto también se puede lograr usando el parámetro de error "out" pasado por referencia)
- Los idiomas generalmente proporcionan alguna facilidad para administrar la limpieza ordenada en el caso de la excepción (prueba / finalmente en Java, usando C #, RAII en C ++)
- En el caso de que no se produzca una excepción, la ejecución a veces puede ser más rápida que verificar los códigos de retorno
- En Java, las excepciones marcadas se deben declarar o capturar (aunque esto puede ser una razón en contra)
Razones para no usar excepciones:
- A veces es excesivo si el manejo de errores es simple
- Si las excepciones no se documentan ni se declaran, es posible que no se detecten mediante el código de llamada, que puede ser peor que si el código de la llamada simplemente ignoró un código de retorno (la salida de la aplicación contra el fallo silencioso, lo que es peor puede depender del escenario)
- En C ++, el código que utiliza excepciones debe ser seguro de excepciones (incluso si no las arrojas o atrapas, sino que llamas a una función de lanzamiento indirectamente)
- En C ++, es difícil saber cuándo se puede lanzar una función, por lo tanto, debe ser paranoico acerca de la seguridad de las excepciones si las usa
- Lanzar y atrapar excepciones generalmente es mucho más costoso en comparación con verificar un indicador de retorno
En general, me sentiría más inclinado a usar excepciones en Java que en C ++ o C #, porque opino que una excepción, declarada o no, es fundamentalmente parte de la interfaz formal de una función, ya que cambiar su garantía de excepción puede romper el código de llamada. La mayor ventaja de usarlos en Java IMO es que sabe que su interlocutor DEBE manejar la excepción, y esto mejora la posibilidad de un comportamiento correcto.
Debido a esto, en cualquier idioma, siempre derivaría todas las excepciones en una capa de código o API de una clase común, por lo que el código de llamada siempre puede garantizar la captura de todas las excepciones. También consideraría malo lanzar clases de excepción que sean específicas de la implementación, al escribir una API o una biblioteca (es decir, ajustar las excepciones de las capas inferiores para que la excepción que recibe el autor de la llamada sea comprensible en el contexto de su interfaz).
Tenga en cuenta que Java hace la distinción entre excepciones generales y de tiempo de ejecución en que estas últimas no necesitan ser declaradas. Solo usaría clases de excepción de Runtime cuando sepa que el error es el resultado de un error en el programa.
Algunas cosas útiles para pensar cuando se decide si una excepción es apropiada:
qué nivel de código desea que se ejecute después de que se produzca la excepción candidata, es decir, cuántas capas de la pila de llamadas deben desenrollarse. Por lo general, desea manejar una excepción lo más cerca posible de donde ocurre. Para la validación de nombre de usuario / contraseña, normalmente manejaría las fallas en el mismo bloque de código, en lugar de dejar que se produzca una excepción. Así que una excepción probablemente no sea apropiada. (OTOH, después de tres intentos fallidos de inicio de sesión, el flujo de control puede cambiar a otra parte, y una excepción puede ser apropiada aquí).
¿Es este evento algo que querría ver en un registro de errores? No todas las excepciones se escriben en un registro de errores, pero es útil preguntar si esta entrada en un registro de errores sería útil, es decir, trataría de hacer algo al respecto o sería la basura que ignora.
Hay dos clases principales de excepción:
1) Excepción del sistema (por ejemplo, pérdida de conexión de la base de datos) o 2) Excepción del usuario. (por ejemplo, validación de entrada de usuario, ''la contraseña es incorrecta'')
Me resultó útil crear mi propia clase de excepción de usuario y cuando deseo lanzar un error de usuario, quiero que me manejen de manera diferente (es decir, el error de recursos que se muestra al usuario), entonces todo lo que necesito hacer en mi controlador de errores principal es verificar el tipo de objeto. :
If TypeName(ex) = "UserException" Then
Display(ex.message)
Else
DisplayError("An unexpected error has occured, contact your help desk")
LogError(ex)
End If
"PasswordNotCorrectException" no es un buen ejemplo para usar excepciones. Es de esperar que los usuarios obtengan sus contraseñas incorrectas, por lo que no es una excepción en mi humilde opinión. Probablemente incluso se recupere de él, mostrando un buen mensaje de error, así que es solo una verificación de validez.
Las excepciones no manejadas detendrán la ejecución eventualmente, lo cual es bueno. Si devuelve códigos falsos, nulos o de error, tendrá que lidiar con el estado del programa por su cuenta. Si olvida verificar las condiciones en algún lugar, su programa puede seguir funcionando con datos incorrectos y puede tener dificultades para averiguar qué sucedió y dónde .
Por supuesto, podría causar el mismo problema con las declaraciones de captura vacías, pero al menos detectarlas es más fácil y no requiere que comprenda la lógica.
Entonces, como regla general:
Úsalos donde no quieras o simplemente no puedas recuperarte de un error.
En última instancia, la decisión se reduce a si es más útil lidiar con errores de nivel de aplicación como este mediante el manejo de excepciones, o mediante su propio mecanismo enrollado en el hogar como los códigos de estado de devolución. No creo que haya una regla estricta sobre cuál es mejor, pero consideraría:
- ¿Quién llama a tu código? ¿Es esta una API pública de algún tipo o una biblioteca interna?
- Qué idioma estás usando? Si se trata de Java, por ejemplo, al lanzar una excepción (marcada) se aplica una carga explícita a su interlocutor para manejar esta condición de error de alguna manera, en lugar de un estado de devolución que podría ignorarse. Eso podría ser bueno o malo.
- ¿Cómo se manejan otras condiciones de error en la misma aplicación? Las personas que llaman no querrán tratar con un módulo que maneja los errores de manera idiosincrásica, a diferencia de cualquier otra cosa en el sistema.
- ¿Cuántas cosas pueden ir mal con la rutina en cuestión y cómo se manejarían de manera diferente? Considere la diferencia entre una serie de bloques de captura que manejan diferentes errores y un interruptor en un código de error.
- ¿Tiene información estructurada sobre el error que necesita devolver? Lanzar una excepción le da un lugar mejor para colocar esta información que simplemente devolver un estado.
En mi opinión, la pregunta fundamental debería ser si uno esperaría que la persona que llama quisiera continuar el flujo normal del programa si se produce una condición. Si no lo sabe, tenga métodos separados de DoSomething y trySomething, donde el primero devuelve un error y el último no, o tiene una rutina que acepta un parámetro para indicar si se debe lanzar una excepción si falla Considere una clase para enviar comandos a un sistema remoto y reportar respuestas. Ciertos comandos (por ejemplo, reinicio) harán que el sistema remoto envíe una respuesta, pero luego no responderá durante un cierto tiempo. Por lo tanto, es útil poder enviar un comando "ping" y averiguar si el sistema remoto responde en un tiempo razonable sin tener que lanzar una excepción si no lo hace.t (la persona que llama probablemente esperaría que los primeros intentos de "ping" fallarían, pero uno eventualmente funcionaría). Por otro lado, si uno tiene una secuencia de comandos como:
exchange_command("open tempfile"); exchange_command("write tempfile data {whatever}"); exchange_command("write tempfile data {whatever}"); exchange_command("write tempfile data {whatever}"); exchange_command("write tempfile data {whatever}"); exchange_command("close tempfile"); exchange_command("copy tempfile to realfile");
Uno querría que una falla de cualquier operación aborte toda la secuencia. Si bien se puede verificar cada operación para garantizar que tenga éxito, es más útil que la rutina exchange_command () lance una excepción si falla un comando.
En realidad, en el escenario anterior puede ser útil tener un parámetro para seleccionar varios modos de manejo de fallas: nunca lanzar excepciones, lanzar excepciones solo por errores de comunicación, o lanzar excepciones en cualquier caso en que un comando no devuelva un "éxito " indicación.
Puede usar un poco de excepciones genéricas para esas condiciones. Por ejemplo, ArgumentException está destinado a usarse cuando algo va mal con los parámetros de un método (con la excepción de ArgumentNullException). En general, no necesitaría excepciones como la excepción LessThanZeroException, NotPrimeNumberException, etc. Piense en el usuario de su método. El número de condiciones que ella querrá manejar específicamente es igual al número del tipo de excepciones que su método debe lanzar. De esta manera, puede determinar qué excepciones detalladas tendrá.
Por cierto, siempre intente proporcionar algunas formas para que los usuarios de sus bibliotecas eviten excepciones. TryParse es un buen ejemplo, existe para que no tenga que usar int.Parse y capturar una excepción. En su caso, es posible que desee proporcionar algunos métodos para verificar si el nombre de usuario es válido o si la contraseña es correcta para que sus usuarios (o usted) no tengan que hacer un montón de manejo de excepciones. Con suerte, esto dará como resultado un código más legible y un mejor rendimiento.
para mí se debe lanzar una excepción cuando falla una regla técnica o de negocios requerida. por ejemplo, si una entidad de automóvil está asociada con un conjunto de 4 llantas ... si una llanta o más son nulas ... una excepción debe ser "Not EnoughTiresException", debe ser capturada en diferentes niveles del sistema y tener una Es decir, a través del registro. además si solo tratamos de fluir controlamos el nulo y evitamos la instanciación del auto. Es posible que nunca encontremos el origen del problema, porque el neumático no debe estar vacío en primer lugar.