has - java ioexception
Cuándo atrapar java.lang.Error? (16)
Casi nunca. Los errores están diseñados para ser problemas que las aplicaciones generalmente no pueden hacer nada al respecto. La única excepción podría ser manejar la presentación del error, pero incluso eso podría no ir según lo previsto dependiendo del error.
¿En qué situaciones se debería capturar java.lang.Error
en una aplicación?
En el entorno multiproceso, lo más frecuente es que quieras atraparlo. Cuando lo captures, lo registras y finalizas toda la aplicación. Si no haces eso, algún hilo que pueda estar haciendo una parte crucial estaría muerto, y el resto de la aplicación pensaría que todo es normal. Fuera de eso, muchas situaciones no deseadas pueden suceder. El problema más pequeño es que no podrá encontrar fácilmente la raíz del problema, si otros hilos comienzan a arrojar algunas excepciones debido a que un hilo no funciona.
Por ejemplo, generalmente el bucle debería ser:
try {
while (shouldRun()) {
doSomething();
}
}
catch (Throwable t) {
log(t);
stop();
System.exit(1);
}
Incluso en algunos casos, es posible que desee manejar diferentes errores de forma diferente, por ejemplo, en OutOfMemoryError podrá cerrar la aplicación regularmente (incluso tal vez liberar algo de memoria, y continuar), en algunos otros, no hay mucho que pueda hacer.
En general, nunca. Sin embargo, a veces es necesario atrapar errores específicos.
Si está escribiendo código marco-ish (cargando clases de terceros), podría ser conveniente detectar LinkageErrors (no se encontró def de clase, enlace insatisfecho, cambio de clase incompatible). También he visto algunos códigos estúpidos de terceros arrojando subcauses de Errores, por lo que también tendrás que manejarlos.
Por cierto, no estoy seguro de que no sea posible recuperarme de OutOfMemory.
En general, siempre debe atrapar java.lang.Error
y escribirlo en un registro o mostrarlo al usuario. Trabajo en apoyo y veo a diario que los programadores no pueden decir qué sucedió en un programa.
Si tiene un hilo daemon, entonces debe evitar que se termine. En otros casos, su aplicación funcionará correctamente.
Solo debe capturar java.lang.Error
al más alto nivel.
Si observa la lista de errores verá que la mayoría se puede manejar. Por ejemplo, se produce un ZipError
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 finalizar su programa.
NoClassDefFoundError
ocurre 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 finalizar su programa.
Puedo dar muchos más ejemplos de por qué es una buena idea capturar Throwable
en el nivel superior y producir un mensaje de error útil.
En una aplicación de Android estoy capturando un java.lang.VerifyError . Una biblioteca que estoy usando no funcionará en dispositivos con una versión anterior del SO y el código de la biblioteca generará un error de este tipo. Por supuesto, pude evitar el error al verificar 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 caída mayor. Algunos dispositivos específicos, aunque se supone que soportan la biblioteca, arrojan excepciones. Capturo VerifyError y todas las Excepciones para usar una solución alternativa.
Idealmente, no deberíamos manejar / detectar errores. Pero puede haber casos en los que tengamos que hacer, según los requisitos del marco o la aplicación. Digamos que tengo un daemon XML Parser que implementa DOM Parser que consume más memoria. Si hay un requisito, como el hilo del Analizador, no debe fallecer cuando obtiene OutOfMemoryError , sino que debe manejarlo y enviar un mensaje / correo al administrador de la aplicación / framework.
Muy raramente.
Diría solo en el nivel superior de un hilo para INTENTAR emitir un mensaje con el motivo de la muerte de un hilo.
Si está en un marco que hace este tipo de cosas para usted, déjelo en el marco.
Muy, muy raramente.
Lo hice solo por un caso conocido muy específico. Por ejemplo, java.lang.UnsatisfiedLinkError podría lanzarse si dos independent ClassLoader 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 necesitó iniciar sesión para saber qué sucedió cuando el usuario vino a quejarse. Quiere un mensaje o una ventana emergente para el usuario, en lugar de silenciarla.
Incluso un programador en C / C ++, aparece un error y dice algo que las personas no entienden antes de salir (por ejemplo, falla de la memoria).
Nunca. Nunca puede estar seguro de que la aplicación puede ejecutar la siguiente línea de código. Si obtiene un OutOfMemoryError
, no tiene garantía de que podrá hacer algo confiablemente . Captura RuntimeException y verifica excepciones, pero nunca errores.
Puede ser apropiado detectar el error dentro de las pruebas unitarias que verifican que se haga una afirmación. Si alguien inhabilita las afirmaciones o elimina la afirmación que desea saber
Se produce un error cuando la JVM no funciona más de lo esperado o está a punto de hacerlo. Si detecta un error, no hay garantía de que se ejecutará el bloque catch, y mucho menos de que se ejecutará hasta el final.
También dependerá de la computadora en funcionamiento, el estado de la memoria actual, por lo que no hay forma de probar, probar y hacerlo lo mejor posible. Solo tendrás un resultado arriesgado.
También degradará la legibilidad de su código.
Si estás lo suficientemente loco como para crear un nuevo marco de pruebas de unidades, es probable que tu corredor de pruebas tenga que atrapar java.lang.AssertionError arrojado por cualquier caso de prueba.
De lo contrario, vea otras respuestas.
Y hay un par de otros casos en los que si detecta un error, debe volver a lanzarlo . Por ejemplo, ThreadDeath nunca debe ser capturado, puede causar un gran problema si lo atrapa en un entorno contenido (por ejemplo, un servidor de aplicaciones):
Una aplicación debe capturar instancias de esta clase solo si debe limpiar después de terminar de forma asincrónica. Si ThreadDeath es capturado por un método, es importante volver a tirarlo para que el hilo realmente muera.
es bastante útil capturar java.lang.AssertionError en un entorno de prueba ...
idealmente, nunca deberíamos detectar el 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 dar como resultado un accidente o dar un resultado gravemente incorrecto.
Por lo general, no se debe atrapar un Error
, ya que indica una condición anormal que nunca debería ocurrir .
De la especificación de API de Java para la clase de Error
:
Un
Error
es una subclase deThrowable
que indica problemas graves que una aplicación razonable no debería intentar atrapar. La mayoría de esos errores son condiciones anormales. [...]No se requiere un método para declarar en su cláusula throws ninguna subclase de Error que pueda lanzarse durante la ejecución del método pero que no se capture, ya que estos errores son condiciones anormales que nunca deberían ocurrir.
Como se menciona en la especificación, un Error
solo se produce en circunstancias que son posibles. Cuando se produce un Error
, la aplicación puede hacer muy poco y, en algunas circunstancias, la máquina virtual Java misma puede estar en un estado inestable (como VirtualMachineError
)
Aunque un Error
es una subclase de Throwable
que significa que puede ser atrapada por una cláusula try-catch
, pero probablemente no sea realmente necesaria, ya que la aplicación se encontrará en un estado anormal cuando la JVM genere un Error
.
También hay una breve sección sobre este tema en la Sección 11.5 Jerarquía de excepciones de la Especificación del lenguaje Java, 2da Edición .