Cuándo usar una aserción y cuándo usar una excepción


121

La mayoría de las veces usaré una excepción para verificar una condición en mi código, me pregunto cuándo es el momento apropiado para usar una afirmación.

Por ejemplo,

Group group=null;
try{
    group = service().getGroup("abc");
}catch(Exception e){
    //I dont log error because I know whenever error occur mean group not found
}

if(group !=null)
{
    //do something
}

¿Podría indicar cómo encaja una aserción aquí? ¿Debo usar una afirmación?

Parece que nunca uso aserciones en el código de producción y solo veo aserciones en pruebas unitarias. Sé que en la mayoría de los casos, solo puedo usar la excepción para hacer la verificación como se indicó anteriormente, pero quiero saber la forma adecuada de hacerlo "profesionalmente".

Respuestas:


81

Las afirmaciones deberían usarse para verificar algo que nunca debería suceder, mientras que una excepción debería usarse para verificar algo que podría suceder.

Por ejemplo, una función puede dividirse por 0, por lo que se debe usar una excepción, pero se puede usar una aserción para verificar que el disco duro desaparezca repentinamente.

Una aserción detendría la ejecución del programa, pero una excepción permitiría que el programa continúe ejecutándose.

Tenga en cuenta que if(group != null)no es una afirmación, es solo un condicional.


3
"una afirmación podría usarse para verificar que el disco duro desaparezca repentinamente". Yo diría que esto no es correcto: ¿por qué querrías que esto se maneje durante el desarrollo, pero no en la producción (cuando las afirmaciones están normalmente desactivadas)?
herman

71
El comentario sobre el disco duro está mal. Las afirmaciones son para verificar errores en la lógica de su código. Nunca, nunca, los uses para verificar algo que no controlas. Recuerde, si una afirmación falla, significa que su código está equivocado .
Ian Goldby

1
@Marius Su condicional podría reemplazarse con una afirmación como esta: afirmar grupo! = Nulo
IgorGanapolsky

1
Votado en contra porque el ejemplo del disco duro contradice su propia filosofía. Los discos duros que "desaparecen" (desde la perspectiva del código) en realidad podrían suceder en realidad, sin importar cuán improbable sea. Como dice @IanGoldby, las afirmaciones deberían depender exclusivamente de las cosas controladas por su código.
Vicky Chijwani

Una respuesta mucho mejor si es publicada por Gregory Pakosz, lea esa publicación.
ormurin

169

Fuera de mi mente (la lista puede estar incompleta y es demasiado larga para caber en un comentario), diría:

  • use excepciones al verificar los parámetros pasados ​​a métodos y constructores públicos o protegidos
  • use excepciones cuando interactúe con el usuario o cuando espere que el código del cliente se recupere de una situación excepcional
  • use excepciones para abordar los problemas que puedan ocurrir
  • use aserciones al verificar condiciones previas, condiciones posteriores e invariantes de código privado / interno
  • use aserciones para proporcionar comentarios a usted mismo o a su equipo de desarrolladores
  • use afirmaciones cuando verifique cosas que es muy poco probable que sucedan, de lo contrario significa que hay un error grave en su aplicación
  • use afirmaciones para decir cosas que (supuestamente) sabe que son ciertas

En otras palabras, las excepciones abordan la solidez de su aplicación, mientras que las aserciones abordan su corrección.

Las afirmaciones están diseñadas para ser baratas de escribir, puedes usarlas en casi todas partes y estoy usando esta regla general: cuanto más estúpida es una declaración de afirmación, más valiosa es y más información incorpora. Al depurar un programa que no se comporta de la manera correcta, seguramente verificará las posibilidades de falla más obvias según su experiencia. Luego verificará los problemas que simplemente no pueden suceder: esto es exactamente cuando las afirmaciones ayudan mucho y ahorran tiempo.


53
Me gusta cómo expresó esto: las excepciones abordan la solidez de su aplicación, mientras que las aserciones abordan su corrección .
M. Dudley


Y si por casualidad buscas una biblioteca de afirmación
Gregory Pakosz el


15

Como regla general:

  • Use aserciones para verificaciones de consistencia interna donde no importa en absoluto si alguien las desactiva. (Tenga en cuenta que el javacomando desactiva todas las aserciones de forma predeterminada).
  • Use pruebas regulares para cualquier tipo de controles que no se deben apagar. Esto incluye controles defensivos que protegen contra posibles daños causados ​​por errores, y cualquier dato / solicitud de validación / lo que sea proporcionado por los usuarios o servicios externos.

El siguiente código de su pregunta tiene un estilo incorrecto y puede presentar errores.

try {
    group = service().getGroup("abc");
} catch (Exception e) {
    //i dont log error because i know whenever error occur mean group not found
}

El problema es que NO sabe que una excepción significa que no se encontró el grupo. También es posible que la service()llamada haya arrojado una excepción, o que haya regresado, lo nullque causó un NullPointerException.

Cuando detecta una excepción "esperada", debe detectar solo la excepción que está esperando. Al detectar java.lang.Exception(y especialmente al no iniciar sesión), está haciendo que sea más difícil diagnosticar / depurar el problema, y ​​potencialmente permitiendo que la aplicación haga más daño.


4

Bueno, de vuelta en Microsoft, la recomendación era lanzar Excepciones en todas las API que pongas a disposición del público y usar Asserts en todo tipo de suposiciones que hagas sobre el código interno. Es una definición un poco floja, pero supongo que depende de cada desarrollador dibujar la línea.

Con respecto al uso de Excepciones, como su nombre lo indica, su uso debe ser excepcional, por lo que para el código que presenta anteriormente, la getGroupllamada debería regresar nullsi no existe ningún servicio. La excepción solo debería ocurrir si un enlace de red se cae o algo así.

Supongo que la conclusión es que queda un poco en manos del equipo de desarrollo para que cada aplicación defina los límites de afirmación frente a excepciones.


En mi humilde opinión, el problema con ese tipo de recomendación es que está bien siempre que el límite entre las partes públicas y privadas de una API sea bastante fijo. Si está desarrollando nuevo código a continuación, ese límite es a menudo bastante fluida ...
Len Holgate

Sí tienes razón. Es una guía, pero al final del día queda fuera de la sensibilidad de los programadores. No creo que haya una línea definitoria definitiva para estos, así que supongo que simplemente sigues con lo que crees que es correcto al leer un montón de código diferente.
rui

3

De acuerdo con este documento http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#design-faq-general , "La declaración de aserción es apropiada para la condición previa no pública, la condición posterior y la clase invariante "La comprobación de la condición previa pública aún debe realizarse mediante comprobaciones dentro de los métodos que dan como resultado excepciones documentadas en particular, como IllegalArgumentException e IllegalStateException".

Si desea obtener más información sobre la condición previa, la condición posterior y la clase invariante, consulte este documento: http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#usage-conditions . También contiene ejemplos de uso de aserciones.


1

La prueba de nulo solo detectará nulos que causan problemas, mientras que un intento / captura como lo hace detectará cualquier error.

En términos generales, try / catch es más seguro, pero un poco más lento, y debe tener cuidado de detectar todos los tipos de error que pueden ocurrir. Entonces diría que use try / catch: un día el código getGroup puede cambiar, y es posible que necesite esa red más grande.


1

Puede usar esta simple diferencia en mente mientras usa. Las excepciones se usarán para verificar los errores esperados e inesperados llamados errores verificados y no verificados, mientras que la aserción se usa principalmente con fines de depuración en el tiempo de ejecución para ver si los supuestos están validados o no.


1

Confieso que estoy un poco confundido por tu pregunta. Cuando no se cumple una condición de aserción, se lanza una excepción. Confusamente esto se llama AssertionError . Tenga en cuenta que no está marcada, como (por ejemplo) IllegalArgumentException, que se produce en circunstancias muy similares.

Entonces, usando aserciones en Java

  1. es un medio más conciso de escribir un bloque de condición / lanzamiento
  2. le permite activar / desactivar estas comprobaciones a través de parámetros JVM. Normalmente dejaría estos controles todo el tiempo, a menos que afecten el rendimiento del tiempo de ejecución o tengan una penalización similar.

AssertionError es una subclase de Error, no RuntimeException.
Stephen C

Ah Por supuesto. Estaba pensando en marcado / no marcado. Ahora corregido
Brian Agnew, el

Explica qué son las afirmaciones (desde un punto de vista controvertido), pero no cuándo usarlas exactamente.
Karl Richter

1

Consulte la sección 6.1.2 (Aserciones versus otro código de error) de la documentación de Sun en el siguiente enlace.

http://www.oracle.com/technetwork/articles/javase/javapch06.pdf

Este documento ofrece los mejores consejos que he visto sobre cuándo usar aserciones. Citando del documento:

"Una buena regla general es que debes usar una afirmación para casos excepcionales de los que te gustaría olvidarte. Una afirmación es la forma más rápida de lidiar y olvidar una condición o estado que no esperas tener que tratar con."


0

Lamentablemente afirma puede ser deshabilitado. Cuando esté en producción, necesita toda la ayuda que pueda obtener al rastrear algo imprevisto, por lo que afirma descalificarse.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.