lanzar excepción de tiempo de ejecución en la aplicación Java

12

Estoy trabajando como contratista diseñando aplicaciones Java empresariales para mi cliente en el rol de líder técnico. La aplicación será utilizada por los usuarios finales y habrá un equipo de soporte que la respaldará cuando nos vayamos.

Los otros clientes potenciales técnicos con los que estoy trabajando tienen la impresión de que el manejo de excepciones ensuciará el código. El sistema debe lanzar excepciones verificadas solo desde el nivel de Servicio y el resto del código debe lanzar excepciones de tiempo de ejecución de todos los demás niveles para que no sea necesario manejar las excepciones no verificadas.

¿Cuál es la necesidad de lanzar una excepción no verificada en una aplicación comercial?

De mi experiencia en el pasado sobre excepciones de tiempo de ejecución:

1) Las excepciones no marcadas hacen que el código sea impredecible porque no se muestran ni siquiera en el Javadoc.

2) Lanzar excepciones no verificadas en una aplicación comercial no tiene sentido porque cuando lo lanzas y va directo a la cara de los usuarios, ¿cómo se lo explicas al usuario? He visto suficientes aplicaciones web que muestran lo 500 -Internal Error. Contact Administratorque no significa nada para un usuario final o para el equipo de soporte que administra la aplicación.

3) Lanzar excepciones de tiempo de ejecución obliga a los usuarios de la clase que lanza la excepción a recorrer el código fuente para depurar y ver por qué se lanza la excepción. Esto solo se puede evitar si el Javadoc de la excepción de tiempo de ejecución está excelentemente documentado, lo que nunca es un caso.

randominstanceOfLivingThing
fuente
¿Puede explicar qué es el nivel de servicio? ¿La capa está más alejada del usuario o la más cercana al usuario?
Manoj R
¿Por qué esta pregunta no cabe en SO?
Bjarke Freund-Hansen
@Manoj R: Ninguno de los dos. Un nivel o capa de servicio es donde se ejecutan las reglas y la lógica de negocios, separadas de los detalles de la tecnología DB y la presentación del cliente.
Michael Borgwardt
66
Las excepciones no verificadas [...] no aparecen incluso en el Javadoc. => aparecerán si los documenta con la @throwsetiqueta, lo que por cierto es una buena práctica.
Assylias
44
@SureshKoya Java efectivo, Elemento 62: Documente todas las excepciones lanzadas por cada método. Extracto: use la @throwsetiqueta Javadoc para documentar cada excepción no verificada que un método puede lanzar, pero no use la palabra clave throws para incluir excepciones no verificadas en la declaración del método.
Assylias

Respuestas:

13

Las excepciones marcadas son un expriment fallido en el diseño del lenguaje. Te obligan a tener abstracciones extremadamente agujereadas y código sucio. Deben evitarse tanto como sea posible.

En cuanto a sus puntos:

1) Las excepciones marcadas ensucian el código y no son menos impredecibles porque aparecen en todas partes .

2) ¿Cómo se muestra mejor una excepción marcada al usuario? La única diferencia real entre las excepciones marcadas y no marcadas es técnica y afecta solo al código fuente.

3) ¿Has oído hablar de los rastros de la pila? Le dicen exactamente dónde se produjo la excepción, sin importar si está marcada o no. En realidad, las excepciones marcadas tienden a ser peores para la depuración porque a menudo se envuelven, lo que conduce a trazas de pila más largas y feas, o incluso se pierden juntas porque el ajuste se realizó incorrectamente.

Hay dos tipos de excepciones: las que ocurren "normalmente" y generalmente se manejan muy cerca de donde ocurren, y las que son realmente excepcionales y se pueden manejar genéricamente en una capa muy alta (simplemente cancele la acción actual y regístrela / muestra un error).

Las excepciones marcadas fueron un intento de poner esta distinción en la sintaxis del lenguaje en el punto en que se definen las excepciones. Los problemas con esto son

  • La distinción depende realmente de la persona que llama , no del código que arroja la excepción
  • Es completamente ortogonal al significado semántico de una excepción, pero vincularlo a la jerarquía de clases te obliga a mezclar los dos
  • Todo el punto de excepciones es que puede decidir a qué nivel capturarlos sin arriesgarse a perder un error en silencio o tener que contaminar el código en niveles intermedios o; las excepciones marcadas pierden esa segunda ventaja.
Michael Borgwardt
fuente
1. Bueno, en caso de una excepción no verificada, ni siquiera sabrá si una llamada podría resultar en una no verificada. 2. Cuando dijiste "Es completamente ortogonal al significado semántico de una excepción, pero vincularlo a la jerarquía de clases te obliga a mezclar los dos", supongo que quisiste decir llamar jerarquía en lugar de jerarquía de clases.
randominstanceOfLivingThing
2
@Suresh Koya: No, me refería a la jerarquía de clases, el hecho de que una declaración SQLException extends Exceptionsignifique que elegir lanzar una SQLExceptionporque un error tiene que ver con el acceso a la base de datos automáticamente significa que la excepción está marcada. Y puede documentar excepciones no verificadas en los comentarios Javadoc muy bien. Funciona bien para todos los demás idiomas.
Michael Borgwardt
1
@MichaelBorgwardt "Las excepciones marcadas son un exprime fallido en el diseño del lenguaje", es su opinión personal si no, me gustaría leer más al respecto. Cualquier enlace auténtico sería de gran ayuda.
Vipin
2
@Vipin: Es mi opinión personal, pero una que muchas otras personas comparten, por ejemplo, Bruce Eckel: mindview.net/Etc/Discussions/CheckedExceptions , y el hecho de que ningún otro idioma ha adoptado excepciones comprobadas en los 20 años desde que se introdujo Java habla por sí mismo ...
Michael Borgwardt
2

Mi opinión es que el tipo de excepción que se produce depende de lo que esté haciendo su código.

Lanzo excepciones comprobadas cuando espero que sucedan con bastante frecuencia (usuarios que ingresan datos dudosos, por ejemplo) y espero que el código de llamada maneje la situación.

Lanzo excepciones no verificadas / en tiempo de ejecución (no tan a menudo como marcadas) cuando tengo una situación rara que no espero que maneje el código de llamada. Un ejemplo podría ser algún tipo de error extraño relacionado con la memoria que nunca espero que ocurra. Sin marcar están los tipos de errores que esperas que la aplicación caiga.

Ninguna excepción debería aparecer frente a un usuario sin algún nivel de soporte. Incluso si es solo un "corte y pegue este volcado de error en un correo electrónico". Nada es más molesto para un usuario que saber que hay un error, pero no recibir detalles ni acciones que puedan tomar para iniciar la reparación.

Supongo que la filosofía que mencionas proviene de una de dos fuentes:

  • Programadores perezosos que intentan evitar trabajar.
  • O desarrolladores que han tenido que soportar código que fue al revés. es decir, manejo de errores excesivos. El tipo de código que contiene grandes cantidades de manejo de excepciones, gran parte del cual no hace nada, o peor aún, se usa para el control de flujo y otros fines incorrectos.
drekka
fuente
Si algo puede suceder con bastante frecuencia, no es una excepción. Pero acordó que no se debe arrojar un error, del cual el usuario no tiene idea.
Manoj R
Estoy de acuerdo con tu filosofía. En una aplicación que está desarrollando para usuarios, ¿cuál será la necesidad de lanzar una excepción de tiempo de ejecución?
randominstanceOfLivingThing
Además, incluso si se produce una excepción de tiempo de ejecución, prefiero la convención que señaló @assylias.
randominstanceOfLivingThing
1

Si no desea excepciones de tiempo de ejecución no verificadas, ¿por qué está utilizando Java? Existe la posibilidad de excepciones de tiempo de ejecución en casi todas partes, en particular las excepciones NullPointerException, ArithmeticException, ArrayIndexOutOfBounds, etc.

Y cuando lea una vez los archivos de registro de algún sistema J2EE, como, por ejemplo, una instalación de SAP NetWeaver, verá que tales excepciones ocurren literalmente todo el tiempo.

Ingo
fuente
De la especificación del lenguaje Java: "Las clases de excepción en tiempo de ejecución (RuntimeException y sus subclases) están exentas de la verificación en tiempo de compilación porque, a juicio de los diseñadores del lenguaje de programación Java, tener que declarar tales excepciones no ayudaría significativamente a establecer la corrección de programas. Muchas de las operaciones y construcciones del lenguaje de programación Java pueden dar lugar a excepciones de tiempo de ejecución ".
randominstanceOfLivingThing
1
La excepción de tiempo de ejecución de la que está hablando son las que surgen de Java, ya que el sistema de tiempo de ejecución de Java no tiene idea de por qué está tratando de hacer la llamada específica. Por ejemplo: surgiría una excepción NullPointerException si está llamando a un método que es nulo. En ese caso, el sistema de tiempo de ejecución de Java no tiene una palabra correcta para la locura de los programadores y golpearía a la persona que llama con una NullPointerException. La parte triste es que la persona que llama le ha vendido el producto Netweaver y usted, como usuario, ahora es víctima de una programación deficiente. Los probadores tienen la misma culpa ya que no hicieron todas las pruebas de límites.
randominstanceOfLivingThing
1

Hay algunas reglas para el manejo de excepciones que debe tener en cuenta. Pero primero, debe recordar que las excepciones son parte de la interfaz expuesta por el código; documentarlos . Esto es especialmente importante cuando la interfaz es pública, por supuesto, pero también es una muy buena idea en las interfaces privadas.

Las excepciones solo deben manejarse en el punto donde el código puede hacer algo sensato con ellas. La peor opción de manejo es no hacer nada al respecto, lo que solo debe hacerse cuando esa es exactamente la opción correcta. (Cuando tengo una situación así en mi código, incluyo un comentario al respecto para que no me preocupe por el cuerpo vacío).

La segunda peor opción es lanzar una excepción no relacionada sin el original adjunto como causa. El problema aquí es que la información dentro de la excepción original que permitiría el diagnóstico del problema se pierde; está creando algo con lo que nadie puede hacer nada (aparte de quejarse de que "no funciona", y todos sabemos cómo odiamos esos informes de errores).

Mucho mejor es registrar la excepción. Eso le permite a alguien descubrir cuál es el problema y solucionarlo, pero solo debe registrar la excepción en el punto en el que de otro modo se perdería o informaría a través de una conexión externa. Esto no se debe a que el registro más frecuente sea un problema importante como tal, sino a que el registro excesivo significa que el registro consume más espacio sin contener más información. Una vez que haya registrado la excepción, puede informar un resumen al usuario / cliente con buena conciencia (siempre y cuando también incluya el tiempo de generación u otro identificador de correlación) en ese informe para que la versión corta pueda coincidir arriba con los detalles si es necesario).

La mejor opción es, por supuesto, manejar completamente la excepción, lidiando con la situación de error en su totalidad. Si puedes hacer esto, ¡hazlo! Incluso podría significar que puede evitar tener que registrar la excepción.

Una forma de manejar una excepción es lanzar otra excepción que proporcione una descripción de nivel superior del problema (por ejemplo, " failed to initialize" en lugar de " index out of bounds"). Este es un buen patrón siempre que no pierda la información sobre la causa de la excepción; use la excepción detallada para inicializar la causeexcepción de nivel superior o registre los detalles (como se discutió anteriormente). El registro es más apropiado cuando está a punto de cruzar un límite entre procesos, como una llamada IPC, porque no hay garantía de que la clase de excepción de bajo nivel esté presente en el otro extremo de la conexión. Mantenerse como una causa adjunta es lo más apropiado al cruzar un límite interno.

Otro patrón que ves es atrapar y soltar:

try {
    // ...
} catch (FooException e) {
    throw e;
}

Este es un antipatrón a menos que tenga restricciones de tipo de otras catchcláusulas que significan que no puede dejar que la excepción pase sola. Entonces es solo una característica fea de Java.

No existe una diferencia real entre las excepciones verificadas y las no verificadas, aparte del hecho de que debe declarar las excepciones verificadas que cruzan los límites del método. Todavía es una buena idea documentar excepciones no verificadas (con el @throwscomentario de javadoc) si sabe que su código las arroja deliberadamente. No arrojes deliberadamente java.lang.Erroro sus subclases (a menos que estés escribiendo una implementación JVM).

Opinión: Un caso de error inesperado siempre representa un error en su código. Las excepciones marcadas son una forma de gestionar esta amenaza, y cuando los desarrolladores usan deliberadamente excepciones no verificadas como una forma de evitar el problema de manejar casos de error, está acumulando una gran cantidad de deudas técnicas que tendrá que limpiar en algún momento si quieres un código robusto El manejo descuidado de errores no es profesional (y observar el manejo de errores es una buena manera de determinar qué tan bueno es realmente un programador).

Compañeros de Donal
fuente
0

Creo que SOLO deberías lanzar una excepción marcada cuando la aplicación pueda recuperarse. Por lo tanto, los usuarios de su biblioteca deben detectar esas excepciones y hacer lo que sea necesario para recuperarse. Cualquier otra cosa debe ser desmarcada.

Como un ejemplo,

Si su aplicación carga datos desde un archivo o una base de datos. Entonces,..

try {
  File data = new File(...);
  // parse file here
} catch (Exception ex) {
  throw new MissingDataFileException("data file not found");
}

la persona que llama siempre puede detectar la MissingDataFileException marcada y luego intentar cargar los datos de la base de datos.

try {
  Connection con = DriverManager.getConnection( host, username, password );
  // query data here
} catch (Exception ex) {
  throw new RuntimeException("better call Saul!");
}
Hendrix
fuente
1
Saúl murió en un accidente automovilístico hace 3 años. ¡Fallar! ;-)
Donal Fellows