¿No es una buena práctica manejar las excepciones de tiempo de ejecución en el código?

11

Estoy trabajando en una aplicación Java, y veo que las excepciones de tiempo de ejecución se manejan en muchos lugares. Por ejemplo,

try {
    // do something
} catch(NullPointerException e) {
    return null;
}

Mi pregunta es, ¿cuándo es una buena práctica manejar las excepciones de tiempo de ejecución? ¿Cuándo deben dejarse de lado las excepciones?

Vinoth Kumar CM
fuente
77
-1: No hay una respuesta única para una pregunta tan amplia y vaga. Es imposible proporcionar una respuesta única a una pregunta tan desenfocada como esta. Esta pregunta es horrible. Proporcione ejemplos específicos de dónde tiene dudas.
S.Lott
@ S.Lott Estoy un poco en desacuerdo en este caso ya que parece que hay un subconjunto de programadores que tienen en mente que este es el caso sin racionalidad "buena".
SoylentGray
2
@Chad: "este es el caso sin" buena "racionalidad". Eso puede ser cierto. Pero la única respuesta posible tiene que ser "depende". Por lo tanto, la pregunta parece defectuosa.
S.Lott

Respuestas:

18

Depende.

Por ejemplo, Integer#parseIntthrows NumberFormatException(que es un RTE) si la cadena proporcionada no se puede analizar. ¿Pero seguramente no desea que su aplicación se bloquee solo porque el usuario escribió "x" en un campo de texto que era para enteros? ¿Y cómo sabes si la cadena se puede analizar, a menos que intentes analizarla primero? Entonces, en este caso, el RTE es solo una señal de error que debería causar algún tipo de mensaje de error. Se podría argumentar que debería ser una excepción marcada, pero ¿qué puede hacer? No lo es.

Joonas Pulakka
fuente
2
Estoy de acuerdo con "Depende", pero su ejemplo de análisis parece ser más bien un caso de mal diseño de API. Integer#parseIntrealmente debería devolver un Maybe<Integer>en su lugar y no lanzar ninguna excepción en absoluto.
Jörg W Mittag
3
@ Jörg W Mittag: estoy de acuerdo en que es un mal diseño de API, pero es el mundo real con el que tenemos que lidiar. Cómo manejar adecuadamente los valores arrojables / devueltos depende de cómo funciona realmente el mundo , no de cómo debería funcionar de manera óptima :-)
Joonas Pulakka
El punto aquí es que puede hacer algo significativo para una condición anticipada (la entrada del usuario no es entera). Solo tragar NPE es un mal estilo y solo cubrirá los errores de programación existentes.
Jürgen Strobel
7

Las excepciones de puntero nulo suelen ser el signo de una comprobación nula faltante. Por lo tanto, en lugar de atraparlo así, debe agregar la verificación nula adecuada para asegurarse de no lanzar la excepción.

Pero a veces, es apropiado manejar RunTimeExceptions. Por ejemplo, cuando no puede modificar el código para agregar la verificación nula en el lugar apropiado, o cuando la excepción no es una excepción NullPointerException.

Su ejemplo de manejo de excepciones es terrible. Al hacerlo, pierde el rastro de la pila y la información precisa sobre el problema. Y en realidad no lo está resolviendo, ya que probablemente desencadenará otra NullPointerException en un lugar diferente y obtendrá información engañosa sobre lo que sucedió y cómo resolverlo.

deadalnix
fuente
1
Me gustaría agregar que una verificación nula es una mejor decisión en cuanto al rendimiento.
Mahmoud Hossam
... aún así, si está haciendo docenas de asignaciones que "nunca deberían fallar" en un lugar, agregar cheques nulos para cada uno de ellos puede ofuscar el código de manera ridícula. Una excepción general (que manejará la situación con gracia, no solo return null;) será una mejor solución.
SF.
Probablemente esté confundiendo Java con algo más (C ++ por ejemplo). Cuando falla una asignación, obtiene un OutOfMemoryError o algo similar, nunca un puntero nulo. Ocultar un retorno nulo en lugar de una excepción es ocultar el error esperando que el código explote en otro lugar.
deadalnix
newtira std::bad_allocen C ++.
R. Martinho Fernandes
Asumiendo que el nuevo operador no está sobrecargado, lo cual es una práctica común. En C ++, cualquier cosa puede suceder;) Pero bueno, digamos C's malloc. El punto importante fue que nunca lo conseguiste en Java.
deadalnix
4

Manejo las excepciones esperadas donde las espero. (Como errores de lectura / escritura de DB). Excepciones inesperadas burbujeo. En otro lugar puede estar esperando la excepción y tener la lógica para ello.

SoylentGray
fuente
2

Las excepciones deberían ser solo eso ... excepciones. La mejor práctica cuando se usan excepciones es usarlas para cubrir la situación en la que sucede algo contrario a lo que cabría esperar. El ejemplo clásico es la FileNotFoundException que se produce cuando un archivo simplemente no está allí. Si está probando la existencia del archivo, entonces usa File.exists () ya que simplemente está presionando con un palo de 10 pies para ver si golpea algo.

Técnicamente, podría lograr los mismos resultados al rodearlo en un intento de captura y usar el archivo como si existiera, pero A) las excepciones son generalmente costosas en cuanto a recursos y B) los programadores van a asumir que usted quiso decir que el archivo existía si era en un intento de captura, que se suma a la confusión general de un programa.

Hay muchas situaciones en las que escribiré un método que obtiene algún valor de una base de datos. Mil cosas podrían salir mal, y viendo que solo necesito una pequeña información, es inconveniente rodear la llamada con una lista de prueba que contiene 5 excepciones diferentes. Entonces, atraparé excepciones en el método fetch. Si algo sale mal, tomo cualquier acción apropiada para cerrar la conexión de la base de datos o cualquier otra cosa en la cláusula final y devuelvo nulo. Esta es una buena práctica no solo porque simplifica su código sino también porque "nulo" envía el mismo mensaje que podría haber recibido de una excepción ... de que algo no salió según lo planeado. Administre detalles de excepción en el método de búsqueda, pero administre qué hacer cuando las cosas no '

Por ejemplo:

Integer getUserCount() {
   Integer result = null;
   try {
      // Attempt to open database and retrieve data
   } catch (TimeoutException e) {
      logger.error("Got a watch?");
   } catch (MissingDatabaseException e) {
      logger.error("What are you smoking?");
   } catch (PermissionsToReadException e) {
      logger.error("Did you *really* think you were getting away with that?");
   } catch (PressedSendButtonToHardException e) {
      logger.error("Seriously.. just back away from the computer... slowly..");
   } catch (WTFException e) {
      logger.error("You're on your own with this one.. I don't even know what happened..");
   } finally {
      // Close connections and whatnot
   }
   return result;
}

void doStuff() {
   Integer result = getUserCount();
   if(result != null) {
       // Went as planned..
   }
}
Neil
fuente
66
Si usa File.exists () y confía en el resultado, podría ocurrir una condición de carrera si el archivo se elimina directamente entre File.exists () y File.open (). Si esto desencadena un error crítico para la seguridad, un atacante podría causar esta condición a propósito. Debido a esto, a veces es mejor mantener la operación atómica, es decir, probarla y detectar la excepción.
user281377
1
Además, hay archivos que deben existir para ejecutar la aplicación. Esas serían condiciones excepcionales. Si hay un archivo que debe tener para que la aplicación funcione, entonces no hay razón para no leerlo y luego manejar la excepción para el caso excepcional. Creo que aclara la intención.
Thomas Owens
Esta es una mala decisión para devolver nulo. Resultará en NullPointerException en algún momento y será muy difícil depurar lo que salió mal. Porque alguien en algún momento olvidará el cheque nulo.
deadalnix
@deadalnix: Podría argumentar que de otra manera podrías olvidarte de rodear con un try-catch. La diferencia es una cuestión de estilo, no de funcionalidad.
Neil
@ammoQ: no estoy de acuerdo. Creo que deberías usar File.exists () y en la rara circunstancia de que se elimine antes de usarlo, una excepción es más que apropiada. La diferencia es donde guardas tu captura. Simplemente tenga un receptor de excepciones general para errores imprevistos para registrarlo e informarlo.
Neil
-5

sí, está manejando correctamente las excepciones de tiempo de ejecución no es una buena práctica. La razón es que se considera costoso / requiere mucha memoria.

prasonscala
fuente
55
Hola prassee, ¿puedes dar más detalles sobre tu respuesta? Las frases que no están respaldadas con hechos, referencias o experiencias no son muy útiles.