10 Ejercicios resueltos de Manejo de Excepciones en Java
Descubre cómo crear programas a prueba de fallos con estos 10 ejercicios resueltos de manejo de excepciones en Java. Aprenderás a usar try-catch, prever errores comunes y construir aplicaciones estables y profesionales. Ideal para afianzar tus conocimientos de nivel intermedio paso a paso.
Aprendizaje teórico
¿Qué es una Excepción?
Una excepción es un evento inesperado que interrumpe el flujo normal de tu programa. Por ejemplo, intentar dividir un número por cero o buscar un archivo que no existe en el disco duro. Si no «atrapas» estos errores, el programa se cerrará abruptamente.
¿Para qué sirve el Manejo de Excepciones?
Sirve para decirle al programa qué hacer exactamente cuando algo sale mal. En lugar de cerrarse con un mensaje incomprensible, puedes mostrarle al usuario un error amigable y permitir que el programa siga funcionando o se cierre de forma segura.
¿Cómo funciona?
Se utiliza un bloque try (intentar) para envolver el código que podría fallar. Si ocurre un error, el programa salta inmediatamente al bloque catch (atrapar), donde manejas el problema. Opcionalmente, puedes usar finally para ejecutar código que siempre debe correr, haya error o no (como cerrar una conexión).
Ejercicio 1: Evitando la división por cero
Escribe un programa que divida dos números enteros, donde el divisor sea cero. Utiliza un bloque try-catch para capturar el error matemático e imprimir un mensaje amigable indicando que la división por cero no está permitida, en lugar de que el programa falle.
Pista
El error específico que Java lanza cuando intentas dividir por cero con números enteros se llama ArithmeticException.
public class Main {
public static void main(String[] args) {
int dividendo = 10;
int divisor = 0;
try {
// Este código generará un error
int resultado = dividendo / divisor;
System.out.println("El resultado es: " + resultado);
} catch (ArithmeticException e) {
// Aquí atrapamos el error
System.out.println("Error: No es posible dividir un número entre cero.");
}
System.out.println("El programa continúa su ejecución normal.");
}
}
terminal Resultado esperado:
Error: No es posible dividir un número entre cero. El programa continúa su ejecución normal.
Ejercicio 2: Acceso seguro a un arreglo
Crea un arreglo de tres nombres. Intenta imprimir el cuarto nombre (índice 3). Captura la excepción correspondiente para evitar que el programa se cuelgue y avisa al usuario que está intentando acceder a una posición que no existe.
Pista
Cuando intentas acceder a un índice fuera de los límites de un arreglo, Java lanza una ArrayIndexOutOfBoundsException.
public class Main {
public static void main(String[] args) {
String[] nombres = {"Ana", "Luis", "Carlos"};
try {
// Intentamos acceder al índice 3 (el cuarto elemento, que no existe)
System.out.println("El nombre es: " + nombres[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Aviso: El índice solicitado está fuera de los límites de la lista.");
}
}
}
terminal Resultado esperado:
Aviso: El índice solicitado está fuera de los límites de la lista.
Ejercicio 3: Conversión de texto a número
Tienes una variable de texto que contiene el valor «25A». Intenta convertir ese texto a un número entero usando Integer.parseInt(). Captura el error de formato y muestra un mensaje indicando que el texto contiene caracteres no válidos.
Pista
El método parseInt espera solo números. Si encuentra letras, lanzará una NumberFormatException.
public class Main {
public static void main(String[] args) {
String textoNumero = "25A";
try {
int numero = Integer.parseInt(textoNumero);
System.out.println("El número convertido es: " + numero);
} catch (NumberFormatException e) {
System.out.println("Error de formato: No se puede convertir '" + textoNumero + "' a un número entero válido.");
}
}
}
terminal Resultado esperado:
Error de formato: No se puede convertir '25A' a un número entero válido.
Ejercicio 4: Uso del bloque finally
Simula la conexión a una base de datos. Dentro de un try, lanza un error intencionalmente (división por cero). Captura el error en el catch. Añade un bloque finally que imprima «Cerrando conexión a la base de datos», garantizando que este mensaje aparezca siempre.
Pista
El bloque finally se coloca justo después del último catch y se ejecuta sin importar si ocurrió una excepción o si el código del try funcionó perfectamente.
public class Main {
public static void main(String[] args) {
System.out.println("Abriendo conexión a la base de datos...");
try {
System.out.println("Ejecutando consulta...");
int errorSimulado = 10 / 0; // Provocamos un fallo
} catch (ArithmeticException e) {
System.out.println("Se produjo un error durante la consulta.");
} finally {
// Este bloque siempre se ejecuta
System.out.println("Cerrando conexión a la base de datos.");
}
}
}
terminal Resultado esperado:
Abriendo conexión a la base de datos... Ejecutando consulta... Se produjo un error durante la consulta. Cerrando conexión a la base de datos.
Ejercicio 5: Capturando múltiples excepciones
Crea un programa que intente dividir el largo de un texto (String) entre un número, pero inicializa el texto como null. Configura un bloque try con dos catch: uno para NullPointerException (que es el que saltará) y otro para ArithmeticException.
Pista
Puedes apilar varios bloques catch debajo de un solo try. Java evaluará de arriba hacia abajo y entrará al primero que coincida con el error ocurrido.
public class Main {
public static void main(String[] args) {
String mensaje = null;
int divisor = 2;
try {
// Esto lanzará NullPointerException porque mensaje no tiene valor
int longitudDividida = mensaje.length() / divisor;
System.out.println("Resultado: " + longitudDividida);
} catch (ArithmeticException e) {
System.out.println("Error matemático detectado.");
} catch (NullPointerException e) {
System.out.println("Error: Intentaste operar con un objeto nulo (vacío).");
}
}
}
terminal Resultado esperado:
Error: Intentaste operar con un objeto nulo (vacío).
Ejercicio 6: Excepciones agrupadas (Multi-catch)
Simplifica el código del ejercicio anterior. En lugar de usar dos bloques catch separados, utiliza la sintaxis de multi-catch (introducida en Java 7) para capturar tanto ArithmeticException como NullPointerException en un solo bloque y mostrar un mensaje de «Error genérico».
Pista
Puedes agrupar excepciones en un solo catch separándolas con el operador de tubería o pipe (|).
public class Main {
public static void main(String[] args) {
String mensaje = null;
int divisor = 2;
try {
int longitudDividida = mensaje.length() / divisor;
System.out.println("Resultado: " + longitudDividida);
} catch (ArithmeticException | NullPointerException e) {
// Captura cualquiera de los dos errores
System.out.println("Fallo de ejecución: Objeto nulo o error matemático.");
// getMessage() imprime detalles técnicos de la excepción
System.out.println("Detalle técnico: " + e.getMessage());
}
}
}
terminal Resultado esperado:
Fallo de ejecución: Objeto nulo o error matemático. Detalle técnico: Cannot invoke "String.length()" because "mensaje" is null
Ejercicio 7: Lanzando excepciones propias con throw
Crea un método llamado verificarEdad(int edad). Si la edad es menor a 18, lanza manualmente una IllegalArgumentException indicando que el usuario es menor de edad. Llama a este método desde el main dentro de un try-catch.
Pista
Usa la palabra clave throw (lanzar) seguida de una nueva instancia (new) de la excepción cuando la condición no se cumpla.
public class Main {
// Método que evalúa y posiblemente lanza el error
public static void verificarEdad(int edad) {
if (edad < 18) {
throw new IllegalArgumentException("Acceso denegado: El usuario debe ser mayor de 18 años.");
}
System.out.println("Acceso concedido. Bienvenido.");
}
public static void main(String[] args) {
try {
verificarEdad(15);
} catch (IllegalArgumentException e) {
// Imprimimos el mensaje que enviamos al lanzar la excepción
System.out.println(e.getMessage());
}
}
}
terminal Resultado esperado:
Acceso denegado: El usuario debe ser mayor de 18 años.
Ejercicio 8: Propagación de excepciones con throws
Escribe un método leerArchivo() que simule una lectura y lance una Exception general. En lugar de manejarla con try-catch dentro del método, utiliza la firma throws para delegar la responsabilidad. Maneja la excepción en el método principal (main).
Pista
Agrega throws Exception al lado de los paréntesis del método leerArchivo(). Esto obliga a quien llame a este método a hacerse cargo del error.
public class Main {
// El método declara que PUEDE lanzar una excepción, pero no la maneja aquí
public static void leerArchivo() throws Exception {
System.out.println("Buscando archivo...");
// Simulamos que el archivo no existe
throw new Exception("El archivo 'datos.txt' no fue encontrado en la ruta.");
}
public static void main(String[] args) {
// Como main llama a un método con 'throws', ESTÁ OBLIGADO a usar try-catch
try {
leerArchivo();
} catch (Exception e) {
System.out.println("Error manejado en el main: " + e.getMessage());
}
}
}
terminal Resultado esperado:
Buscando archivo... Error manejado en el main: El archivo 'datos.txt' no fue encontrado en la ruta.
Ejercicio 9: Creando tu propia Excepción Personalizada
Crea una clase SaldoInsuficienteException que herede de Exception. Luego, crea una clase CuentaBancaria con saldo y un método para retirar dinero. Si el retiro supera el saldo, lanza tu excepción personalizada y captúrala en el main.
Pista
Para crear una excepción personalizada, solo necesitas crear una clase que extienda de Exception (o RuntimeException) y crear un constructor que pase el mensaje al super().
// 1. Creamos nuestra excepción personalizada
class SaldoInsuficienteException extends Exception {
public SaldoInsuficienteException(String mensaje) {
super(mensaje);
}
}
// 2. Usamos la excepción en nuestra lógica
class CuentaBancaria {
private double saldo = 100.0;
public void retirar(double monto) throws SaldoInsuficienteException {
if (monto > saldo) {
throw new SaldoInsuficienteException("No tienes suficiente dinero. Saldo actual: $" + saldo);
}
saldo -= monto;
System.out.println("Retiro exitoso. Nuevo saldo: $" + saldo);
}
}
public class Main {
public static void main(String[] args) {
CuentaBancaria cuenta = new CuentaBancaria();
try {
cuenta.retirar(150.0); // Intentamos retirar más de lo que hay
} catch (SaldoInsuficienteException e) {
System.out.println("Operación fallida: " + e.getMessage());
}
}
}
terminal Resultado esperado:
Operación fallida: No tienes suficiente dinero. Saldo actual: $100.0
Ejercicio 10: Try-with-resources (Cierre automático)
Desde Java 7, existe una forma de cerrar recursos (como archivos o conexiones) automáticamente sin usar finally. Utiliza un bloque «try-with-resources» con un objeto Scanner (que implementa AutoCloseable) para leer una entrada simulada, sabiendo que se cerrará solo.
Pista
El «try-with-resources» se escribe declarando el recurso entre paréntesis justo después de la palabra try: try (Scanner sc = new Scanner(System.in)) { ... }.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// El Scanner se declara DENTRO de los paréntesis del try.
// Al terminar el bloque try, Java llama automáticamente a sc.close().
String textoSimulado = "Hola, estoy aprendiendo excepciones";
try (Scanner sc = new Scanner(textoSimulado)) {
System.out.println("Leyendo datos...");
String palabra = sc.next();
System.out.println("Primera palabra leída: " + palabra);
// Simulemos un error aquí, el Scanner igual se cerrará de fondo
int forzarError = 1 / 0;
} catch (ArithmeticException e) {
System.out.println("Ocurrió un error, pero el Scanner se cerró automáticamente de forma segura.");
}
}
}
terminal Resultado esperado:
Leyendo datos... Primera palabra leída: Hola, Ocurrió un error, pero el Scanner se cerró automáticamente de forma segura.
Preguntas frecuentes
¿Cuál es la diferencia entre Exception y RuntimeException?
Las excepciones que heredan de Exception son «verificadas» (checked); el compilador de Java te obliga a usar try-catch o throws. Las que heredan de RuntimeException son «no verificadas» (unchecked); ocurren por fallos lógicos en ejecución y el compilador no te obliga a manejarlas explícitamente.
¿Qué diferencia hay entre throw y throws?
throw (en singular) se usa DENTRO del código para lanzar intencionalmente un error en un momento específico. throws (en plural) se usa en la DECLARACIÓN del método para avisar que dicho método podría generar un error que otra parte del código deberá solucionar.
¿Puedo usar un bloque try sin un catch?
Sí, pero solo si utilizas un bloque finally o la estructura «try-with-resources». El objetivo mínimo de un bloque try es garantizar o el manejo del error (catch) o la limpieza y cierre de recursos al finalizar (finally).
Conclusión
El manejo de excepciones es lo que diferencia a un código frágil de una aplicación profesional y robusta. Como has practicado en estos ejercicios, interceptar errores a tiempo mejora la experiencia del usuario y protege la integridad de los datos. Ahora sabes cómo prevenir cierres inesperados, delegar la responsabilidad de los errores y crear tus propias alertas personalizadas. Continúa aplicando estos bloques preventivos en tus proyectos personales, especialmente cuando trabajes con ingresos de texto, lecturas de archivos o bases de datos.
Sigue aprendiendo
Documentación oficial de Oracle sobre el manejo y la captura estructurada de excepciones.
Guía completa para entender cómo crear tus propios errores personalizados y cuándo utilizarlos.
Explicación técnica sobre la sentencia que permite el cierre seguro y automático de recursos en Java.
Herramientas recomendadas para practicar
Java es un lenguaje de programación orientado a objetos, tipado y multiplataforma, respaldado por la JVM. Su principio de «escribe una vez, ejecuta en cualquier lugar» lo hace útil para sistemas empresariales, microservicios en la nube, escritorio y Android.
Sigue practicando
Otros ejercicios prácticos recomendados
10 Ejercicios resueltos de Genéricos y Colecciones en Java
Aprende a dominar los genéricos y las colecciones en Java con esta guía práctica. Descubre cómo crear código más seguro, flexible y reutilizable a través de 10 ejercicios resueltos paso a paso, ideales para afianzar tus...
10 Ejercicios resueltos de Archivos y Directorios en Java
Aprende a gestionar archivos y directorios en Java con estos 10 ejercicios resueltos. Descubre cómo crear, leer, escribir y organizar carpetas paso a paso. Práctica ideal para afianzar tus conocimientos intermedios y apl...
10 Ejercicios resueltos de ArrayList y HashMap en Java
Aprende a gestionar colecciones de datos dinámicas con estos 10 ejercicios resueltos de ArrayList y HashMap en Java. Mejora tu lógica de programación, organiza la información eficientemente y domina el nivel intermedio c...