¿Cuándo detectar java.lang.Error?


Respuestas:


101

Generalmente, nunca.

Sin embargo, a veces es necesario detectar errores específicos.

Si está escribiendo un código similar a un marco (cargando clases de terceros), podría ser aconsejable detectar LinkageError (no se encontró una definición de clase, enlace insatisfecho, cambio de clase incompatible).

También he visto algunos códigos de terceros estúpidos que arrojan subclases de Error, por lo que también tendrás que manejarlos.

Por cierto, no estoy seguro de que no sea posible recuperarse OutOfMemoryError.


3
Eso tenía que hacer exactamente para cargar archivos DLL, eso fallaría si no estuvieran configurados correctamente. No es un error fatal en el caso de esta aplicación.
Mario Ortegón

7
A veces tiene sentido detectar OutOfMemoryError, por ejemplo, cuando está creando listas de matrices grandes.
SpaceTrucker

3
@SpaceTrucker: ¿ese enfoque funciona bien en aplicaciones multiproceso o existe un riesgo significativo de que las asignaciones más pequeñas en otros subprocesos fallen debido a él? ... presumiblemente solo si sus matrices fueran lo suficientemente pequeñas para ser asignadas, pero no dejaran nada para nadie más.
PJTraill

@PJTraill No estoy seguro de eso. Esto requeriría algunas muestras estadísticas del mundo real. Pensé que había visto ese código, pero no recuerdo dónde estaba.
SpaceTrucker

51

Nunca. Nunca puede estar seguro de que la aplicación pueda ejecutar la siguiente línea de código. Si obtiene una OutOfMemoryError, no tiene garantía de que podrá hacer algo de manera confiable . Capture RuntimeException y verifique Excepciones, pero nunca Errores.

http://pmd.sourceforge.net/rules/strictexception.html


27
Nunca digas nunca. tenemos código de prueba que hace una "afirmación falsa"; luego detecta el AssertionError para asegurarse de que el indicador -ea esté establecido. Aparte de eso ... sí, probablemente nunca ;-)
Programador fuera de la ley

3
¿Qué tal una aplicación de servidor que entrega las solicitudes a los hilos de trabajo? ¿No tendría sentido capturar Throwable en el hilo de trabajo para atrapar cualquier error y al menos intentar registrar lo que salió mal?
Leigh

11
Nunca ... excepto cuando sea absolutamente necesario. Nunca es una palabra fuerte y siempre hay excepciones a las reglas. Si está construyendo un marco, no es tan improbable que tenga que detectar y manejar ciertos errores, incluso si es solo para iniciar sesión.
Robin

¿Qué hay de los errores, por ejemplo, NoSuchMethodError que proviene de métodos de biblioteca de terceros?
ha9u63ar

@OutlawProgrammer Solo para que conste, hay otras formas de hacer la misma prueba:boolean assertionsEnabled = false; assert assertionsEnabled = true;
shmosel

16

Por lo general, siempre debe capturarlo java.lang.Errory escribirlo en un registro o mostrárselo al usuario. Trabajo en soporte y veo a diario que los programadores no pueden saber qué ha sucedido en un programa.

Si tiene un subproceso de demonio, debe evitar que se termine. En otros casos, su aplicación funcionará correctamente.

Solo debes atrapar java.lang.Erroral más alto nivel.

Si observa la lista de errores, verá que la mayoría se puede manejar. Por ejemplo, ZipErrorocurre al leer archivos zip corruptos.

Los errores más comunes son OutOfMemoryErrory NoClassDefFoundError, que en la mayoría de los casos son problemas de tiempo de ejecución.

Por ejemplo:

int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];

puede producir un OutOfMemoryErrorpero es un problema de tiempo de ejecución y no hay razón para terminar su programa.

NoClassDefFoundErrorocurren principalmente si una biblioteca no está presente o si trabaja con otra versión de Java. Si es una parte opcional de su programa, entonces no debe terminar su programa.

Puedo dar muchos más ejemplos de por qué es una buena idea detectar Throwableen el nivel superior y producir un mensaje de error útil.


Sospecho que es mejor en esos casos fallar al demonio con las alertas adecuadas y luego tener la posibilidad de que permanezca vivo como un fantasma etéreo en una jvm fallida donde podría dar el falso pretexto de que está realmente vivo y haciendo algo
Andrew Norman

OutOfMemoryErrorno es un error de tiempo de ejecución, no hay garantía de que la aplicación pueda recuperarse. Si tiene suerte, puede obtener OOM, new byte[largeNumber]pero si esa asignación no fue suficiente para causar OOM, podría activarse en la siguiente línea o en el siguiente hilo. Este es un problema de tiempo de ejecución porque si lengthno es una entrada confiable, debe validarse antes de llamar new byte[].
Jeeyoung Kim

NoClassDefFoundErrorpuede ocurrir en cualquier lugar , ya que se invoca cuando el código java compilado no puede encontrar una clase. Si su JDK está mal configurado, puede dispararse al intentar usar la java.util.*clase y es prácticamente imposible programar en él. Si opcionalmente incluye una dependencia, debe usar ClassLoaderpara verificar si existe, lo que arroja ClassNotFoundException.
Jeeyoung Kim

1
ZipErrorindica que el archivo jar que contiene las clases es un archivo zip dañado. Este es un problema bastante serio y en este punto no puede confiar en ningún código que se ejecute y sería irresponsable intentar "recuperarse" de él.
Jeeyoung Kim

2
En general, puede ser útil detectar java.lang.Erroro java.lang.Throwableen el nivel superior e intentar hacer algo con él, por ejemplo, registrar un mensaje de error. Pero en ese momento no hay garantía de que esto se lleve a cabo. Si su JVM está en OOM, intentar iniciar sesión puede asignar más mensajes de correo electrónico, lo Stringque activa otro OOM.
Jeeyoung Kim

15

En un entorno multiproceso, lo más frecuente es que desee atraparlo. Cuando lo detecte, regístrelo y finalice toda la aplicación. Si no lo hace, algún hilo que pudiera estar haciendo una parte crucial estaría muerto, y el resto de la aplicación pensará que todo es normal. Fuera de eso, pueden suceder muchas situaciones no deseadas. Un problema menor es que no podría encontrar fácilmente la raíz del problema si otros subprocesos comienzan a generar algunas excepciones debido a que un subproceso no funciona.

Por ejemplo, normalmente el bucle debería ser:

try {
   while (shouldRun()) {
       doSomething();
   }
}
catch (Throwable t) {
   log(t);
   stop();
   System.exit(1);
}

Incluso en algunos casos, querrá manejar diferentes Errores de manera diferente, por ejemplo, en OutOfMemoryError podría cerrar la aplicación regularmente (incluso tal vez liberar algo de memoria y continuar), en algunos otros, no hay mucho que pueda hacer.


1
Detectar OutOfMemoryError y continuar en lugar de existir rápidamente no es prudente porque su programa se encuentra en un estado indefinido .
Raedwald

1
llamar al sistema, salir al atrapar un elemento arrojadizo tiene la consecuencia involuntaria de matar todo lo que se ejecuta en la JVM y no solo la aplicación en cuestión. Por lo general, no es una buena práctica para las aplicaciones web que pueden estar alojadas en un servidor de aplicaciones con otras aplicaciones web (sin mencionar que afectaría al servidor de aplicaciones en sí).
Andrew Norman

9

Muy raramente.

Yo diría que solo en el nivel superior de un hilo para INTENTAR emitir un mensaje con el motivo de la muerte del hilo.

Si está en un marco que hace este tipo de cosas por usted, déjelo en el marco.


6

Casi nunca. Los errores están diseñados para ser problemas sobre los que las aplicaciones generalmente no pueden hacer nada. La única excepción podría ser manejar la presentación del error, pero incluso eso podría no salir según lo planeado dependiendo del error.


6

Por lo Errorgeneral, no se debe detectar , ya que indica una condición anormal que nunca debería ocurrir .

De la especificación de la API de Java para la Errorclase:

An Errores una subclase de Throwable que indica problemas graves que una aplicación razonable no debería intentar detectar. La mayoría de estos errores son condiciones anormales. [...]

No se requiere que un método declare en su cláusula throws cualquier subclases de Error que puedan ser lanzadas durante la ejecución del método pero no detectadas, ya que estos errores son condiciones anormales que nunca deberían ocurrir.

Como menciona la especificación, un Errorsolo se lanza en circunstancias que son Es probable que, cuando Errorocurra un , haya muy poco que la aplicación pueda hacer y, en algunas circunstancias, la máquina virtual Java en sí misma puede estar en un estado inestable (como VirtualMachineError)

Aunque an Errores una subclase de lo Throwableque significa que puede ser capturado por una try-catchcláusula, pero probablemente no sea realmente necesario, ya que la aplicación estará en un estado anormal cuando Errorla JVM lance an .

También hay una sección breve sobre este tema en la Sección 11.5 La jerarquía de excepciones de la especificación del lenguaje Java, 2ª edición .


6

Si está lo suficientemente loco como para crear un nuevo marco de prueba unitario, su ejecutor de prueba probablemente necesitará detectar java.lang.AssertionError arrojado por cualquier caso de prueba.

De lo contrario, vea otras respuestas.


5

Y hay un par de otros casos en los que si detecta un error, debe volver a lanzarlo . Por ejemplo, ThreadDeath nunca debe detectarse , puede causar un gran problema si lo detecta en un entorno contenido (por ejemplo, un servidor de aplicaciones):

Una aplicación debería capturar instancias de esta clase solo si debe limpiarse después de terminar de forma asincrónica. Si ThreadDeath es detectado por un método, es importante que se vuelva a lanzar para que el hilo muera.


2
Lo que en realidad no es un problema porque simplemente no detecta Errors.
Bombe

4

Muy, muy raramente.

Lo hice solo para un caso conocido muy muy específico. Por ejemplo, java.lang.UnsatisfiedLinkError podría lanzarse si dos ClassLoader independientes cargan la misma DLL. (Estoy de acuerdo en que debería mover el JAR a un cargador de clases compartido)

Pero el caso más común es que necesitaba iniciar sesión para saber qué sucedió cuando el usuario llegó a quejarse. Quieres un mensaje o una ventana emergente para el usuario, en lugar de morir silenciosamente.

Incluso programadores en C / C ++, muestran un error y dicen algo que la gente no entiende antes de salir (por ejemplo, falla de memoria).


3

En una aplicación de Android, estoy detectando un java.lang.VerifyError . Una biblioteca que estoy usando no funcionará en dispositivos con una versión anterior del sistema operativo y el código de la biblioteca arrojará ese error. Por supuesto, podría evitar el error comprobando la versión del sistema operativo en tiempo de ejecución, pero:

  • El SDK compatible más antiguo puede cambiar en el futuro para la biblioteca específica
  • El bloque de error try-catch es parte de un mecanismo de retroceso más grande. Algunos dispositivos específicos, aunque se supone que son compatibles con la biblioteca, arrojan excepciones. Detecto VerifyError y todas las excepciones para usar una solución alternativa.

3

es bastante útil detectar java.lang.AssertionError en un entorno de prueba ...


¿Qué valor estás intentando agregar?
lpapp

agregando el valor de un conjunto de pruebas que no se aborta
Jono

2

Idealmente, no deberíamos manejar / detectar errores. Pero puede haber casos en los que debamos hacerlo, según el requisito del marco o la aplicación. Digamos que tengo un demonio XML Parser que implementa DOM Parser que consume más memoria. Si hay un requisito, como el hilo del analizador, no debe morir cuando obtiene OutOfMemoryError , en su lugar, debe manejarlo y enviar un mensaje / correo al administrador de la aplicación / marco.


1

idealmente, nunca deberíamos detectar un error en nuestra aplicación Java, ya que es una condición anormal. La aplicación se encontraría en un estado anormal y podría provocar que se produjera una avería o un resultado gravemente incorrecto.


1

Podría ser apropiado detectar errores dentro de las pruebas unitarias que verifican que se realiza una afirmación. Si alguien deshabilita las aserciones o elimina la aserción, le gustaría saber


1

Hay un error cuando la JVM ya no funciona como se esperaba o está a punto de hacerlo. Si detecta un error, no hay garantía de que el bloque catch se ejecute, y menos aún de que se ejecute hasta el final.

También dependerá de la computadora en ejecución, el estado actual de la memoria, por lo que no hay forma de probar, intentar hacerlo lo mejor posible. Solo tendrás un resultado desastroso.

También degradará la legibilidad de su código.

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.