Cuando estamos programando, no todos los errores se producen cuando compilamos el código, sino que también se pueden producir errores en tiempo de ejecución. A estos errores que ocurren cuando ejecutamos el programa, se les conoce con el nombre de excepción. En este post, hablaré del tratamiento de excepciones en java.
Vamos a distinguir dos tipos de excepciones: las chequeadas y las no chequeadas. Por las primeras entendemos aquellas que manejamos en nuestro código con instrucciones que proporciona el lenguaje de programación, en el caso de Java serían los bloques try – cath. Y por excepciones no chequeadas entenderemos aquellas que no tratamos en nuestro código.
Excepciones no chequeadas
Las excepciones no chequeadas son errores de nuestro código que dependen de nosotros y debiéramos ser capaces de evitar empleando técnicas de programación segura. Un ejemplo clásico de este tipo de excepciones es la división por cero, que arroja un número infinito que el ordenador no puede tratar.
En la siguiente actividad, practicamos el manejo de las excepciones no chequeadas.
Actividad: Manejo de excepciones no chequeadas
- Empezamos abriendo un proyecto nuevo para practicar con las excepciones. En mi caso, le pongo de nombre al proyecto: PracticandoConExcepciones.
- Elimino los comentarios y me queda el código inicial:
public class PracticandoConExcepciones {
public static void main(String[] args) {
}
}
- De momento nada nuevo. Vamos a crear ahora un código que nos genere un error de programación que se manifieste en tiempo de ejecución. Por ejemplo, la división por cero.
- Nuestro código sería:
public class PracticandoConExcepciones {
public static void main(String[] args) {
double dividendo=45;
double divisor=0;
double resultado;
resultado = dividendo/divisor;
System.out.println("el resultado de la división es: "+ resultado);
}
}
- Con este código estamos realizando una división por cero que nos arrojaría la correspondiente excepción en ejecución. Mostrándonos un error. En este caso, NetBeans es capaz de evitarlo ya que este es un error tan habitual que ya lo tiene contemplado. Si ejecutamos el programa obtendremos:
run:
el resultado de la división es: Infinity
BUILD SUCCESSFUL (total time: 0 seconds)
- Se trata de un error tan básico que el compilador es capaz de tratarlo automáticamente. No obstante, es un error y nosotros no queremos que se produzca. El resultado infinito no nos vale para nada y no podemos operar con él.
- ¿Cómo prevenir este error?: Aplicando programación segura que en muchos casos se limita a comprobar los valores antes de operar con ellos.
- Pero mejor, veamos otro ejemplo muy habitual de excepción no chequeada que esta vez no solucione el compilador. Se trata del error: NullPointerException, intentamos leer el contenido de una variable que no contiene nada, que es nula. Por ejemplo, tecleamos el código siguiente:
public class PracticandoConExcepciones {
public static void main(String[] args) {
String texto;
texto=null;
texto.toUpperCase();
}
}
- En este código intentamos acceder al String texto para, usando la función toUpperCase, pasar el texto a mayúsculas. Pero el texto es nulo, no tenemos nada. Si ejecutamos el programa, obtendremos el siguiente error:
run:
Exception in thread "main" java.lang.NullPointerException
at practicandoconexcepciones.PracticandoConExcepciones.main(PracticandoConExcepciones.java:9)
C:\Users\Jegarcia\AppData\Local\NetBeans\Cache\8.2\executor-snippets\run.xml:53: Java returned: 1
BUILD FAILED (total time: 0 seconds)
- Donde vemos la excepción arrojada: NullPointerException. Para evitar esta excepción con prácticas de programación segura, sencillamente tendremos que comprobar antes que el String no es nulo. Haríamos algo parecido a:
public class PracticandoConExcepciones {
public static void main(String[] args) {
String texto;
texto=null;
if (texto!=null){
texto.toUpperCase();
}
}
}
- Si ejecutáramos ahora el programa, veremos que ya no se produce el error. Y a partir de este punto, podemos programar la respuesta para este caso. Por ejemplo, pedirle al usuario que introduzca un texto:
import java.util.Scanner;
public class PracticandoConExcepciones {
public static void main(String[] args) {
String texto;
texto=null;
if (texto==null){
Scanner sc= new Scanner(System.in);
System.out.println("Por favor, introduce un texto: ");
texto = sc.nextLine();
}
System.out.println("El texto en mayusculas es: "+texto.toUpperCase());
}
}
- Si ejecutamos ahora el programa, un posible resultado sería:
run:
Por favor, introduce un texto:
Hola amigo
El texto en mayusculas es: HOLA AMIGO
BUILD SUCCESSFUL (total time: 7 seconds)
- Otra excepción no chequeada muy frecuente es: ArrayIndexOutOfBoundsException. Como su nombre indica, se produce cuando intentamos acceder a un elemento de un array empleando un índice que está fuera del rango. Por ejemplo si tenemos un array de 5 elementos e intentamos acceder al elemento array[5], nos daría esta excepción (recordemos que los índices de los arrays empiezan en 0, así que para un array de 5 elementos el rango de índices es 0-4)
- El alumno puede probar a reproducir esta excepción programando su propio código.
Excepciones chequeadas
Las excepciones chequeadas son aquellas que dependen del entorno y nosotros, como programadores, no tenemos manera de evitarlas. Lo que tenemos que hacer es asegurarnos de que las tratamos. Un ejemplo clásico de este tipo de excepciones es cuando el usuario nos tiene que proporcionar algún dato y lo hace de forma incorrecta. Por ejemplo, nos tiene que proporcionar la ruta a un fichero y lo hace mal, con lo que al intentar acceder al fichero no podremos y obtendríamos un error.
Para tratar estas excepciones, Java provee los bloques try – catch que el compilador nos va a obligar a utilizar cuando una operación tenga riesgo de arrojar una excepción, como por ejemplo abrir un fichero.
Las excepciones no chequeadas, que veíamos en el apartado anterior, también pueden ser tratadas en el código con un bloque try – catch, pero es más recomendable evitarlas con prácticas de programación segura en lugar de permitir que ocurran y tratarlas después.
Como siempre, practiquemos estos conceptos en una actividad.
Actividad: Manejo de excepciones chequeadas
- Continuamos trabajando en el proyecto: PracticandoConExcepciones.
- Para practicar las excepciones chequeadas, vamos a realizar un programa que cree un fichero y que introduzca una serie de datos en el mismo. Aunque todavía no hemos visto la clase File para el manejo de ficheros, aquí tendremos un pequeño adelanto para ver cómo tratar las excepciones con los bloques try-catch. Veremos también, que el compilador nos obliga a tratar este tipo de excepciones.
- Tecleamos el siguiente código:
import java.io.File;
public class PracticandoConExcepciones {
public static void main(String[] args) {
File fichero;
fichero = new File("/pruebas/prueba.txt");
fichero.createNewFile();
}
}
- Nos hemos creado un objeto tipo File que en realidad es la ruta a nuestro fichero. Para crear el fichero empleamos la función createNewFile(). No hay que preocuparse de momento por el manejo de esta Clase, en el próximo cuaderno veremos el manejo de ficheros.
- De momento, lo que vemos es que el compilador nos indica el siguiente error:
Unreported exception IOException, must be caugth o declare to be thrown.
- Nos fuerza a tratar la excepción, nos dice que tenemos que tratar la excepción que podría causarse al ejecutar esta instrucción.
- Esa excepción no es un error de programación. Puede deberse por ejemplo a que no exista el directorio donde queremos crear el fichero, un error de entorno imposible de evitar por programación, por lo que hay que asegurarnos de que los tratamos en nuestro código.
- Si clicamos en el icono que nos da el aviso de que tenemos que tratar la excepción, el compilador nos da algunas opciones. Vamos a escoger la opción:
Surround statement with try-catch.
- Y nuestro código quedaría:
import java.io.File;
import java.io.IOException;
public class PracticandoConExcepciones {
public static void main(String[] args) {
File fichero;
fichero = new File("/pruebas/prueba.txt");
try {
fichero.createNewFile();
} catch (IOException ex) {
System.out.println("el error es: "+ex);
}
}
}
- Podemos ver, que la sentencia que nos puede arrojar la excepción, en la línea 11, la hemos introducido dentro del bloque try. El código de la línea 13 lo introducimos nosotros para enseñar por pantalla la excepción que se produce.
- Así funciona el bloque try-catch. Colocamos en el bloque try las sentencias que queramos ejecutar que puedan causar una excepción. Y en el bloque catch colocamos las sentencias que emplearemos para tratar esa posible excepción
- El bloque catch recibe como parámetro la excepción que se ha producido. Sin embargo, ahora el programa no se interrumpirá arrojando un error, sino que se pasará a ejecutar las instrucciones en el bloque catch.
- Si ejecutamos este programa, obtenemos:
run:
el error es: java.io.IOException: El sistema no puede encontrar la ruta especificada
BUILD SUCCESSFUL (total time: 0 seconds)
- Vemos que se produce una excepción que nos indica que la ruta donde hemos querido crear el fichero no se encuentra. Normal, es que no existe, no he creado la carpeta pruebas.
- Tratamos la excepción dentro de un bloque catch, escribiendo la misma por pantalla y el programa sigue su curso, ejecutando la línea 13. Pero el programa no ha fallado y ni se ha interrumpido delante del usuario, sino que hemos tratado la excepción y el programa ha finalizado de manera ordenada.
Para entender un poco mejor como funciona los bloques try-catch, vamos a introducir algunas líneas más en nuestro código. Dibujando mensajes por pantalla podremos entender mejor el flujo de nuestro programa. El código queda:
import java.io.File;
import java.io.IOException;
public class PracticandoConExcepciones {
public static void main(String[] args) {
File fichero;
fichero = new File("/pruebas/prueba.txt");
try {
System.out.println("voy a crear el fichero");
fichero.createNewFile();
System.out.println("acabo de crear el fichero");
} catch (IOException ex) {
System.out.println("el error es: "+ex);
System.out.println("Se ha producido una excepción");
}
System.out.println("Ahora continuo haciendo cosas");
}
}
- Las nuevas líneas introducidas son sentencias simples para presentar por pantallas distintos mensajes que indican el momento en el que estamos en el programa.
- Las dos primeras líneas del bloque try:
System.out.println("voy a crear el fichero");
fichero.createNewFile();
Siempre se ejecutarán. Si se produjera una excepción en la segunda, el programa saltaría al bloque catch. Si tal excepción no se produce, continúa ejecutando las instrucciones en el bloque try y cuando acaba, sin que se produzcan excepciones, no ejecuta el bloque catch y continua con el código. En este caso, en la línea 18.
- Si ejecutamos el programa sin crear la carpeta pruebas, generaríamos la excepción y el resultado sería:
run:
voy a crear el fichero
el error es: java.io.IOException: El sistema no puede encontrar la ruta especificada
Se ha producido una excepción
Ahora continuo haciendo cosas
BUILD SUCCESSFUL (total time: 0 seconds)
- Por el contrario, si creamos la carpeta, el resultado de la ejecución sería:
run:
voy a crear el fichero
acabo de crear el fichero
Ahora continuo haciendo cosas
BUILD SUCCESSFUL (total time: 0 seconds)
La clausula Finally
Viendo cómo funciona el bloque try-catch, podemos echar en falta una funcionalidad. No tenemos forma de hacer que un conjunto de instrucciones se ejecute siempre, con independencia de que se produzca la excepción o no. Podríamos duplicar el código en ambos bloques, try y catch, pero esto es bastante ineficiente.
Esta situación se da en no pocas ocasiones. Por ejemplo, trabajando con ficheros, debiéramos cerrar los objetos una vez utilizados, empleando el método close, se haya producido excepción o no. Si estamos intentando acceder a una base de datos, tendríamos básicamente la misma situación.
Para dar solución a este tema, java introduce un bloque adicional al try-catch, el bloque finally. Vamos a verlo en un ejemplo con un fichero.
Actividad: Entendiendo la clausula finally
- Continuamos trabajando en el proyecto: PracticandoConExcepciones. Recupero aquí el último código que tecleamos:
import java.io.File;
import java.io.IOException;
public class PracticandoConExcepciones {
public static void main(String[] args) {
File fichero;
fichero = new File("/pruebas/prueba.txt");
try {
System.out.println("voy a crear el fichero");
fichero.createNewFile();
System.out.println("acabo de crear el fichero");
} catch (IOException ex) {
System.out.println("el error es: "+ex);
System.out.println("Se ha producido una excepción");
}
System.out.println("Ahora continuo haciendo cosas");
}
}
- Para probar el uso de finally, añadimos la cláusula con un mensaje. Aunque no tiene mucho sentido, nos ayuda a probar y entender el funcionamiento de finally. El código podría ser:
import java.io.File;
import java.io.IOException;
public class PracticandoConExcepciones {
public static void main(String[] args) {
File fichero;
fichero = new File("/pruebas/prueba.txt");
try {
System.out.println("voy a crear el fichero");
fichero.createNewFile();
System.out.println("acabo de crear el fichero");
} catch (IOException ex) {
System.out.println("el error es: "+ex);
System.out.println("Se ha producido una excepción");
}
finally {
System.out.println("esto se ejecuta siempre, haya o no excepción");
}
System.out.println("Ahora continuo haciendo cosas");
}
}
- Si ejecutamos este código, como no se produce excepción, el resultado sería:
run:
voy a crear el fichero
acabo de crear el fichero
esto se ejecuta siempre, haya o no excepción
Ahora continuo haciendo cosas
BUILD SUCCESSFUL (total time: 0 seconds)
- Lo siguiente que haremos será provocar una excepción para analizar el comportamiento de finally en este caso. Para ello, cambiamos el nombre de la carpeta donde íbamos a crear el fichero, poniendo un carpeta que no exista.
- Si ejecutamos el programa obtenemos el siguiente resultado:
run:
voy a crear el fichero
el error es: java.io.IOException: El sistema no puede encontrar la ruta especificada
Se ha producido una excepción
esto se ejecuta siempre, haya o no excepción
Ahora continuo haciendo cosas
BUILD SUCCESSFUL (total time: 0 seconds)
En ambos casos, podemos ver que las instrucciones dentro del bloque finally se ejecutan siempre, haya o no excepción.
NOTA: Este post es parte de la colección “Java”. Puedes ver el índice de esta colección aquí.

