1. Tipos de excepciones

Todas las excepciones se dividen en 4 tipos, que en realidad son clases que se heredan entre sí.
Throwable
clase
La clase base para todas las excepciones es la Throwable
clase. La Throwable
clase contiene el código que escribe la pila de llamadas actual (seguimiento de la pila del método actual) en una matriz. Aprenderemos qué es un seguimiento de pila un poco más tarde.
El operador throw solo puede aceptar un objeto que se deriva de la Throwable
clase. Y aunque teóricamente puedes escribir código como throw new Throwable();
, nadie suele hacer esto. El propósito principal de la Throwable
clase es tener una sola clase principal para todas las excepciones.
Error
clase
La siguiente clase de excepción es la Error
clase, que hereda directamente la Throwable
clase. La máquina Java crea objetos de la Error
clase (y sus descendientes) cuando se han producido problemas graves . Por ejemplo, un mal funcionamiento del hardware, memoria insuficiente, etc.
Por lo general, como programador, no hay nada que pueda hacer en una situación en la que Error
se ha producido un error de este tipo (el tipo por el cual se debe lanzar un) en el programa: estos errores son demasiado graves. Todo lo que puede hacer es notificar al usuario que el programa falla y/o escribir toda la información conocida sobre el error en el registro del programa.
Exception
clase
Las clases Exception
y RuntimeException
son para errores comunes que ocurren en la operación de muchos métodos. El objetivo de cada excepción lanzada es ser atrapado por un catch
bloque que sepa cómo manejarlo correctamente.
Cuando un método no puede completar su trabajo por algún motivo, debe notificar de inmediato al método que llama lanzando una excepción del tipo apropiado.
En otras palabras, si una variable es igual a null
, el método arrojará un NullPointerException
. Si se pasaron los argumentos incorrectos al método, generará un InvalidArgumentException
. Si el método divide accidentalmente por cero, arrojará un ArithmeticException
.
RuntimeException
clase
RuntimeExceptions
son un subconjunto de Exceptions
. Incluso podríamos decir que RuntimeException
es una versión ligera de las excepciones ordinarias ( Exception
): se imponen menos requisitos y restricciones a tales excepciones
Aprenderás la diferencia entre Exception
y RuntimeException
más adelante.
2. Throws
: excepciones marcadas
Todas las excepciones de Java se dividen en 2 categorías: marcadas y no marcadas .
Todas las excepciones que heredan RuntimeException
o Error
se consideran excepciones no verificadas . Todos los demás son excepciones marcadas .
Veinte años después de que se introdujeran las excepciones verificadas, casi todos los programadores de Java piensan que esto es un error. En los marcos modernos populares, el 95% de todas las excepciones no están marcadas. El lenguaje C#, que casi copió Java exactamente, no agregó excepciones comprobadas .
¿ Cuál es la principal diferencia entre las excepciones marcadas y no marcadas ?
Hay requisitos adicionales impuestos a las excepciones marcadas . A grandes rasgos, son estos:
Requisito 1
Si un método arroja una excepción comprobada , debe indicar el tipo de excepción en su firma . De esa manera, cada método que lo llame es consciente de que esta "excepción significativa" podría ocurrir en él.
Indique las excepciones marcadas después de los parámetros del método después de la throws
palabra clave (no use la throw
palabra clave por error). Se ve algo como esto:
type method (parameters) throws exception
Ejemplo:
excepción comprobada | excepción no verificada |
---|---|
|
|
En el ejemplo de la derecha, nuestro código arroja una excepción no verificada : no se requiere ninguna acción adicional. En el ejemplo de la izquierda, el método arroja una excepción verificadathrows
, por lo que la palabra clave se agrega a la firma del método junto con el tipo de excepción.
Si un método espera lanzar múltiples excepciones verificadas , todas ellas deben especificarse después de la throws
palabra clave, separadas por comas. El orden no es importante. Ejemplo:
public void calculate(int n) throws Exception, IOException
{
if (n == 0)
throw new Exception("n is null!");
if (n == 1)
throw new IOException("n is 1");
}
Requisito 2
Si llama a un método que ha verificado excepciones en su firma, no puede ignorar el hecho de que las arroja.
Debe capturar todas esas excepciones agregando catch
bloques para cada una o agregándolas a una throws
cláusula para su método.
Es como si estuviéramos diciendo: " Estas excepciones son tan importantes que debemos atraparlas. Y si no sabemos cómo manejarlas, entonces cualquiera que pueda llamar a nuestro método debe ser notificado de que tales excepciones pueden ocurrir en él".
Ejemplo:
Imagina que estamos escribiendo un método para crear un mundo poblado por humanos. El número inicial de personas se pasa como argumento. Por lo tanto, debemos agregar excepciones si hay muy pocas personas.
Creando la Tierra | Nota |
---|---|
|
El método arroja potencialmente dos excepciones comprobadas :
|
Esta llamada de método se puede manejar de 3 maneras:
1. No atrape ninguna excepción
Esto se hace con mayor frecuencia cuando el método no sabe cómo manejar adecuadamente la situación.
Código | Nota |
---|---|
|
El método de llamada no detecta las excepciones y debe informar a otros sobre ellas: las agrega a su propia throws cláusula |
2. Captura algunas de las excepciones
Manejamos los errores que podemos manejar. Pero los que no entendemos, los lanzamos al método de llamada. Para hacer esto, necesitamos agregar su nombre a la cláusula throws:
Código | Nota |
---|---|
|
La persona que llama detecta solo una excepción marcadaLonelyWorldException : . La otra excepción debe agregarse a su firma, indicándola después de la throws palabra clave |
3. Atrapa todas las excepciones
Si el método no arroja excepciones al método de llamada, entonces el método de llamada siempre confía en que todo funcionó bien. Y no podrá tomar ninguna medida para solucionar situaciones excepcionales.
Código | Nota |
---|---|
|
Todas las excepciones se capturan en este método. La persona que llama estará segura de que todo salió bien. |
3. Envolviendo excepciones
Las excepciones marcadas parecían geniales en teoría, pero resultaron ser una gran frustración en la práctica.
Suponga que tiene un método súper popular en su proyecto. Se llama desde cientos de lugares en su programa. Y decide agregarle una nueva excepción marcada . Y bien puede ser que esta excepción marcada sea realmente importante y tan especial que solo el main()
método sepa qué hacer si se detecta.
Eso significa que tendrá que agregar la excepción marcadathrows
a la cláusula de cada método que llame a su método súper popular . Así como en la throws
cláusula de todos los métodos que llaman a esos métodos. Y de los métodos que llaman a esos métodos.
Como resultado, las throws
cláusulas de la mitad de los métodos del proyecto obtienen una nueva excepción comprobada . Y, por supuesto, su proyecto está cubierto por pruebas, y ahora las pruebas no se compilan. Y ahora también debe editar las cláusulas throws en sus pruebas.
Y luego todo su código (todos los cambios en cientos de archivos) tendrá que ser revisado por otros programadores. Y en este punto nos preguntamos por qué hicimos tantos cambios sangrientos al proyecto. Día(s) de trabajo y pruebas rotas, ¿todo por agregar una excepción verificada ?
Y, por supuesto, todavía hay problemas relacionados con la herencia y la anulación de métodos. Los problemas que surgen de las excepciones verificadas son mucho mayores que el beneficio. La conclusión es que ahora pocas personas los aman y pocas personas los usan.
Sin embargo, todavía hay mucho código (incluido el código de la biblioteca Java estándar) que contiene estas excepciones comprobadas . ¿Qué hay que hacer con ellos? No podemos ignorarlos, y no sabemos cómo manejarlos.
Los programadores de Java propusieron envolver las excepciones comprobadas en RuntimeException
. En otras palabras, capture todas las excepciones verificadas y luego cree excepciones no verificadas (por ejemplo, RuntimeException
) y tírelas en su lugar. Hacer eso se parece a esto:
try
{
// Code where a checked exception might occur
}
catch(Exception exp)
{
throw new RuntimeException(exp);
}
No es una solución muy bonita, pero no hay nada criminal aquí: la excepción simplemente se metió dentro de un archivo RuntimeException
.
Si lo desea, puede recuperarlo fácilmente desde allí. Ejemplo:
Código | Nota |
---|---|
|
Obtenga la excepción almacenada dentro del RuntimeException objeto. La cause variable puede null determinar su tipo y convertirla en un tipo de excepción verificada . |
4. Captura de múltiples excepciones
Los programadores realmente odian duplicar el código. Incluso se les ocurrió un principio de desarrollo correspondiente: Don't Repeat Yourself (DRY) . Pero cuando se manejan excepciones, hay ocasiones frecuentes en las que un try
bloque es seguido por varios catch
bloques con el mismo código.
O puede haber 3 catch
bloques con el mismo código y otros 2 catch
bloques con otro código idéntico. Esta es una situación estándar cuando su proyecto maneja las excepciones de manera responsable.
A partir de la versión 7, en el lenguaje Java se agregó la capacidad de especificar múltiples tipos de excepciones en un solo catch
bloque. Se ve algo como esto:
try
{
// Code where an exception might occur
}
catch (ExceptionType1 | ExceptionType2 | ExceptionType3 name)
{
// Exception handling code
}
Puedes tener tantos catch
bloques como quieras. Sin embargo, un solo catch
bloque no puede especificar excepciones que se hereden entre sí. En otras palabras, no puede escribir catch ( Exception
| RuntimeException
e), porque la RuntimeException
clase hereda Exception
.
5. Excepciones personalizadas
Siempre puede crear su propia clase de excepción. Simplemente crea una clase que hereda la RuntimeException
clase. Se verá algo como esto:
class ClassName extends RuntimeException
{
}
Hablaremos de los detalles a medida que aprenda programación orientada a objetos, herencia, constructores y anulación de métodos.
Sin embargo, incluso si solo tiene una clase simple como esta (totalmente sin código), aún puede generar excepciones basadas en ella:
Código | Nota |
---|---|
|
Lanzar un desmarcado MyException . |
En la misión Java Multithreading , profundizaremos en el trabajo con nuestras propias excepciones personalizadas.
GO TO FULL VERSION