Programación Orientada a Objetos 12 - Excepciones

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.

¿Qué son las Excepciones?

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.

Tipos de Excepciones

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
        }
    }
                

Bloque Try-Catch

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
    }
                

Creación de Excepciones Personalizadas

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);
        }
    }
                

Ejemplo: Manejo de Errores en un Sistema de Gestión de Archivos

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());
            }
        }
    }    
                

¿Qué es el Bloque Finally?

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.

Características del Bloque Finally

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.

Ejemplo de Uso del Bloque Finally

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.

Conclusiones

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.