Respuestas:
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
.
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.
boolean assertionsEnabled = false; assert assertionsEnabled = true;
Por lo general, siempre debe capturarlo java.lang.Error
y 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.Error
al más alto nivel.
Si observa la lista de errores, verá que la mayoría se puede manejar. Por ejemplo, ZipError
ocurre al leer archivos zip corruptos.
Los errores más comunes son OutOfMemoryError
y 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 OutOfMemoryError
pero es un problema de tiempo de ejecución y no hay razón para terminar su programa.
NoClassDefFoundError
ocurren 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 Throwable
en el nivel superior y producir un mensaje de error útil.
OutOfMemoryError
no 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 length
no es una entrada confiable, debe validarse antes de llamar new byte[]
.
NoClassDefFoundError
puede 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 ClassLoader
para verificar si existe, lo que arroja ClassNotFoundException
.
ZipError
indica 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.
java.lang.Error
o java.lang.Throwable
en 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 String
que activa otro OOM.
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.
OutOfMemoryError
y continuar en lugar de existir rápidamente no es prudente porque su programa se encuentra en un estado indefinido .
Por lo Error
general, 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 Error
clase:
An
Error
es una subclase deThrowable
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 Error
solo se lanza en circunstancias que son Es probable que, cuando Error
ocurra 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 Error
es una subclase de lo Throwable
que significa que puede ser capturado por una try-catch
cláusula, pero probablemente no sea realmente necesario, ya que la aplicación estará en un estado anormal cuando Error
la 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 .
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.
Error
s.
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).
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:
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.
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.