Aunque intentamos explicar como programar en java sin cometer errores, somos conscientes que esa perfección nunca la conseguiremos; que nuestros programas tendrán errores, y, cuando los corrijamos, quedaran los usuarios, si, esos entes que tienen la capacidad de encontrar el único agujero que nos quedó, y hacer, que todo nuestro castillo de naipes (aplicación), se venga al suelo de una manera vergonzosa. Y es por todo ello, que necesitamos que nuestro programa sea capaz de enterarse de los errores que aparecen, y procesarlos.
Las listas de errores
Primero de todo, tengamos en cuenta los dos grandes grupos de excepciones que podemos maneja:
Por un lado, tenemos el grupo de las «Unchecked exceptions«. En este apartado se engloban las excepciones que provienen de errores de programación, y que no estamos obligados a manejar; dejando que sea la máquina virtual la que se encargue de ello:
Excepción | Descripción |
ArithmeticException | Error aritmetico; Ej: división por cero |
ArrayIndexOutOfBoundsException | Indice de array fuera de rango. Se esta intentando acceder a un array con un indice mayor que el tamaño del array, o menor de 0 |
ArrayStoreException | Se intenta guardar en un array un tipo incompatible |
ClassCastException | Cast invalido |
IllegalArgumentException | Llamada a un módulo con un argumento ilegal |
IllegalMonitorStateException | Funcionamiento del monitor ilegal, como la espera de un subproceso desbloqueado. |
IllegalStateException | Entorno o aplicación en un estado erroneo |
IllegalThreadStateException | La operación solicitada, no es compatible con el estado del proceso |
IndexOutOfBoundsException | Algun indice está fuera de rango |
NegativeArraySizeException | Array creado con un tamaño negativo |
NullPointerException | Uso invalido de la referencia null |
NumberFormatException | Conversion de string a numero, erronea |
SecurityException | Intento de violación de seguridad |
StringIndexOutOfBounds | Intento de acceso a una posición de string que no existe |
UnsupportedOperationException | Se ha encontrado una operación no soportada |
En el segundo grupo, tenemos las «Checked exceptions», que son las que suceden por hechos ajenos al funcionamiento normal del programa. La mayoría de ellas, están relacionadas con la entrada salida, o con la adquisición de valores erróneos. Estas, java nos obliga a tenerlas en cuenta, capturandolas, o pasándoselas al método superior de forma explicita, hasta que llegue a la máquina virtual:
Excepcion | Descripcion |
ClassNotFoundException | La clase no existe |
CloneNotSupportedException | Intento de clonar un objeto que no implementa la interfaz Cloneable |
IllegalAccessException | Acceso a la clase, denegado |
InstantiationException | Intento de crear un objeto desde una clase no instanciable |
InterruptedException | Un subproceso, ha sido interrumpido por otro subproceso |
NoSuchFieldException | el campo solicitado, no existe |
NoSuchMethodException | El método solicitado, no existe |
Capturando los mensajes de excepción
Para poder capturar la excepción, en java, tenemos la posibilidad de rodear las zonas en donde se pueda generar con la estructura :
try {
instrucciones a mantener bajo control
}
catch (Exception e){
instrucciones a ejecutar en caso de error
}
finally {
instrucciones a ejecutar siempre, aunque se produzca error
}
Si revisamos estos bloques, tenemos :
El try inicia el bloque de instrucciones que se deben ejecutar normalmente y en las que se puede producir algún error.
El catch inicia los bloques en los que se maneja la excepción, y deberemos indicarle qué excepción queremos manejar. Podremos poner tantos bloques catch como excepciones tengamos que manejar:
try { ........... instrucciones a ejecutar, que pueden causar alguna excepción ............ } catch (IndexOutOfBoundsException e) { ............... instrucciones para manejar la IndexOutOfBoundsException.. ........... } catch (IOException e) { ............. instrucciones para manejar otra excepción (en este caso, cualquier otra excepción, ya que Exception es genérico. ............. }
Por último, la clausula finally, representa un bloque por el que se ha de pasar siempre. Haya o no haya error. Normalmente se utilizará para liberar recurso, o cerrar ficheros…
} finally { if (out != null) { System.out.println("Closing PrintWriter"); out.close(); } else { System.out.println("PrintWriter not open"); } }
A partir de Java 7, cuando el motivo es cerrar conexiones, podemos ahorrarnos el finally, especificando los recursos a cerrar a continuación de la clausula try
try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readLine(); }
Cabe destacar que no es necesario codificar catch, si no queremos capturar una excepción, aun así. podemos seguir utilizando finally para realizar algún proceso que se requiera aunque el try salga por error:
BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { if (br != null) br.close(); }
Aunque, por ejemplo, en este caso, deberemos especificar que nuestro método genera una excepción, ya que si no la capturamos nosotros, deberemos dejar que pase:
static String read(String path) throws IOException {
Generando/lanzando excepciones
Puede haber ocasiones, en que nos interese lanzar una excepción desde nuestro código. Para hacerlo, disponemos de una instrucción:
throw new laExcepcion
Para poderlo hacer, utilizaremos un objeto ya existente que herede de java.lang.Throwable
Creando nuevas excepciones
Si podemos lanzar excepciones, también es interesante que podamos crearlas y no tener que depender únicamente de las que nos proporciona Java.
Para crear una excepción, solo tenemos que definir una clase que herede de Exception o RuntimeException.
Deberemos preparar el constructor por defecto, y un segundo constructor que reciba un atributo String describiendo la razón de la excepción
Por ejemplo, esta clase podría ser una nueva excepción:
public class SaldoInsuficiente extends RuntimeException { publicSaldoInsuficiente() {} public SaldoInsuficiente(String message) { super(message); } }