Excepciones, la herramienta de la programación orientada a objetos para manejar errores, algo esencial para crear aplicaciones robustas y confiables.
En este capítulo exploraremos el uso de esta herramienta para manejar errores y situaciones inesperadas, y discutiremos las mejores prácticas para gestionar estos eventos.
Las excepciones son eventos disruptivos que ocurren durante la ejecución de un programa y alteran el flujo normal de las instrucciones.
En Java son objetos que encapsulan la información del error, lanzados cuando ocurre algo inesperado.
Capturarlas y manejarlas adecuadamente es crucial para prevenir fallos y comportamientos no deseados.
Java clasifica las excepciones en dos categorías principales:
Excepciones Verificadas (Checked Exceptions): Son excepciones que se deben capturar o declarar en un método. Estas son situaciones que, aunque inesperadas, son previsibles y recuperables, como la ausencia de un archivo, pero obliga a considerar el error en el invocador.
class Checked {
// Declara la posible Excepcion, para que el
// usuario del método sepa y atrape el error
public static void main(String[] args) throws IOException {
// Creando el Archivo
FileReader file = new FileReader("C:\\file.txt");
BufferedReader fileInput = new BufferedReader(file);
System.out.println(fileInput.readLine());
// Cerrando conexion con el archivo
fileInput.close();
}
}
Excepciones No Verificadas (Unchecked Exceptions): Son errores que reflejan problemas en el código o condiciones imprevisibles. No es obligatorio manejarlas, y generalmente se deben evitar, como un error de división por cero. En caso de error falla y rompe el programa.
class Unchecked {
public static void main(String[] args) {
int x = 0;
int y = 10;
int z = y / x; // Tira error
}
}
El bloque try-catch es la estructura principal para manejar excepciones en Java. Se encierra al código que podría lanzar una excepción dentro de un bloque try, y mediante bloques catch permite manejar diferentes tipos de excepciones que podrían ser lanzadas.
try {
// Código que puede lanzar una excepción
} catch (TipoExcepcion1 e) {
// Manejo de TipoExcepcion1
} catch (TipoExcepcion2 e) {
// Manejo de TipoExcepcion2
}
Java permite crear tus propias clases de excepciones para representar situaciones específicas de error. Esto se hace extendiendo la clase Exception o RuntimeException, dependiendo de si se quiere crear una excepción verificada o no verificada.
public class MiExcepcion extends Exception {
public MiExcepcion(String mensaje) {
super(mensaje);
}
}
Consideremos un simple sistema de gestión de archivos, que lee el contenido de un archivo.
Debemos lidiar con situaciones como archivos que no existen o no tienen permisos de lectura.
Clase GestorArchivos, lanza excepciones:
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class GestorArchivos {
public String leerArchivo(String ruta) throws MiExcepcion {
File archivo = new File(ruta);
if (!archivo.exists()) {
throw new MiExcepcion("El archivo no existe.");
}
try (FileReader reader = new FileReader(archivo)) {
// Lógica para leer el contenido del archivo
return "Contenido del archivo";
} catch (IOException e) {
throw new MiExcepcion("Error lectura: " + e.getMessage());
}
}
}
Uso del GestorArchivos:
public class Principal {
public static void main(String[] args) {
GestorArchivos gestor = new GestorArchivos();
try {
String contenido = gestor.leerArchivo("path/archivo.txt");
System.out.println(contenido);
} catch (MiExcepcion e) {
System.err.println("Error: " + e.getMessage());
}
}
}
El bloque finally es una sección que siempre se ejecuta después de los bloques try y catch, independientemente de si se lanzó una excepción o no.
Es el lugar ideal para colocar código de limpieza, como cerrar archivos o liberar recursos, asegurando que estas operaciones se realicen sin importar lo que ocurra en los bloques try y catch.
Ejecución Garantizada: El bloque finally se ejecutará siempre, haya o no una excepción. La única excepción a esta regla es si hay un System.exit() en el bloque try o catch.
Liberar recursos: Es comúnmente usado para cerrar recursos como flujos de entrada/salida o conexiones a bases de datos, para evitar problemas de rendimiento.
Vamos a expandir el ejemplo del sistema de gestión de archivos para incluir un bloque finally que garantice que el FileReader se cierre correctamente.
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class GestorArchivos {
public String leerArchivo(String ruta) throws MiExcepcion {
File archivo = new File(ruta);
FileReader reader = null;
if (!archivo.exists()) {
throw new MiExcepcion("El archivo no existe.");
}
try {
reader = new FileReader(archivo);
// Lógica para leer el contenido del archivo
return "Contenido del archivo";
} catch (IOException e) {
throw new MiExcepcion("Error de lectura:" + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// Manejo del error al intentar cerrar el recurso
System.err.println("Error al cerrar: " + e.getMessage());
}
}
}
}
}
En este código, incluso si ocurre una excepción al leer el archivo o si se lanza una MiExcepcion, el bloque finally se asegura de que el FileReader se cierre correctamente.
El manejo efectivo de excepciones es fundamental para construir aplicaciones confiables y fáciles de mantener.
Comprender cómo funcionan las excepciones en Java, cómo crear tus propias excepciones y cómo utilizar bloques try-catch para manejar situaciones inesperadas te permitirá escribir código más robusto y resistente a errores.
Adoptar prácticas sólidas de manejo de errores no solo mejorará la calidad de tus aplicaciones, sino que también las hará más seguras y agradables para el usuario final.