Excepciones personalizadas
Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 60 de 87.
Las excepciones integradas de Java cubren muchos escenarios de error comunes, pero a veces se necesitan excepciones que sean específicas del dominio de su aplicación. Las excepciones personalizadas le permiten crear tipos de error significativos que comunican claramente qué salió mal.
Para crear una excepción personalizada, simplemente extiende una clase de excepción existente. Para una excepción verificada, extiende Exception:
public class InsufficientFundsException extends Exception {
public InsufficientFundsException(String message) {
super(message);
}
}Para una excepción no comprobada, extienda RuntimeException:
public class InvalidAgeException extends RuntimeException {
public InvalidAgeException(String message) {
super(message);
}
}La llamada super(message) pasa el mensaje de error a la clase padre, haciéndolo disponible a través de getMessage(). Luego puedes lanzar y capturar tu excepción personalizada como cualquier otra:
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("Balance too low: " + balance);
}
balance -= amount;
}
// Uso
try {
account.withdraw(1000);
} catch (InsufficientFundsException e) {
System.out.println(e.getMessage());
}Las excepciones personalizadas hacen que tu código sea más legible y permiten que quienes llaman al código manejen condiciones de error específicas de manera diferente. Son especialmente valiosas al construir APIs o librerías donde la comunicación clara de errores es importante.
Desafío
Fácil¡Vamos a construir un sistema de reserva de boletos que utiliza excepciones personalizadas para manejar diferentes escenarios de error! Crearás tipos de excepciones significativos que comuniquen claramente qué salió mal al reservar boletos.
Organizarás tu código en cuatro archivos:
TicketSoldOutException.java: Crea una excepción verificada (checked exception) personalizada (extiende deException) para cuando los boletos ya no estén disponibles. Tu excepción debe aceptar un mensaje en su constructor y pasarlo a la clase padre usandosuper(message).InvalidSeatException.java: Crea una excepción no verificada (unchecked exception) personalizada (extiende deRuntimeException) para cuando alguien intente reservar un número de asiento inválido. Esta excepción también debe aceptar y pasar un mensaje a su padre.TicketBooth.java: Crea una clase que gestione la venta de boletos. Tu taquilla debe rastrear el número total de asientos disponibles y el número de asiento válido más alto. Incluye:Un constructor que reciba el número total de asientos disponibles.
Un método
bookTicket(int seatNumber)que valide la reserva. Si no quedan boletos (los asientos disponibles son 0 o menos), lanza unaTicketSoldOutExceptioncon el mensaje"No tickets remaining". Si el número de asiento es menor que 1 o mayor que el total de asientos, lanza unaInvalidSeatExceptioncon el mensaje"Seat " + seatNumber + " does not exist". De lo contrario, disminuye los asientos disponibles en 1 e imprime"Booked seat " + seatNumber + " successfully".Un método
getAvailableSeats()que devuelva el recuento actual de asientos disponibles.Main.java: ¡Une tu sistema de boletos! Recibirás dos entradas: el número total de asientos y un número de asiento para reservar.Crea un
TicketBoothcon el total de asientos dado. Luego, intenta reservar el número de asiento especificado dentro de un bloque try-catch. Dado queTicketSoldOutExceptiones verificada, debes manejarla. CapturaTicketSoldOutExceptionprimero e imprime"Booking failed: " + e.getMessage(). Luego capturaInvalidSeatExceptione imprime el mismo formato:"Booking failed: " + e.getMessage().Después del bloque try-catch, imprime
"Remaining seats: " + booth.getAvailableSeats()usando el método getter.
Recibirás dos entradas en orden: total de asientos (entero) y número de asiento a reservar (entero).
Observa cómo las excepciones verificadas obligan a quienes llaman al método a manejarlas (con try-catch o throws), mientras que las excepciones no verificadas no requieren un manejo explícito. ¡Elige el tipo de excepción basándote en si el error es algo que quienes llaman al método deben anticipar y de lo cual deben recuperarse!
Hoja de referencia
Para crear una excepción personalizada, extiende una clase de excepción existente.
Para una excepción verificada (checked exception), extiende Exception:
public class InsufficientFundsException extends Exception {
public InsufficientFundsException(String message) {
super(message);
}
}Para una excepción no verificada (unchecked exception), extiende RuntimeException:
public class InvalidAgeException extends RuntimeException {
public InvalidAgeException(String message) {
super(message);
}
}La llamada super(message) pasa el mensaje de error a la clase base, haciéndolo disponible a través de getMessage().
Lanza y captura excepciones personalizadas como cualquier otra excepción:
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("Balance too low: " + balance);
}
balance -= amount;
}
// Using it
try {
account.withdraw(1000);
} catch (InsufficientFundsException e) {
System.out.println(e.getMessage());
}Las excepciones verificadas obligan a quienes llaman al método a manejarlas con try-catch o throws. Las excepciones no verificadas no requieren un manejo explícito. Elige basándote en si el error es algo que quienes llaman al método deben anticipar y de lo cual deben recuperarse.
Pruébalo tú mismo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int totalSeats = scanner.nextInt();
int seatNumber = scanner.nextInt();
// TODO: Crear un TicketBooth con el total de asientos dado
// TODO: Usar un bloque try-catch para intentar reservar el asiento
// - Capturar TicketSoldOutException primero e imprimir "Booking failed: [exception message]"
// - Capturar InvalidSeatException e imprimir "Booking failed: [exception message]"
// TODO: Después del try-catch, imprimir "Remaining seats: [count]"
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a la OOPClases vs. ObjetosLa palabra clave thisMétodosCampos (Atributos)Método constructorSobrecarga de constructoresResumen - Calculadora simple4Herencia
Herencia básica (extends)La palabra clave superSobrescritura de métodos (@Override)Encadenamiento de constructoresLa clase ObjectHerencia simple y multinivelPor qué no hay herencia múltiple de clasesResumen - Jerarquía de empleados7Métodos especiales y la clase Object
Método toString()equals() y hashCode()Método clone()compareTo() y ComparableInterfaz ComparatorResumen - Ordenamiento personalizado10Manejo de excepciones en POO
Jerarquía de clases de excepcionesExcepciones personalizadasErrores Checked vs UncheckedPatrón Try With ResourcesResumen - Usuario validado2Modificadores de acceso y encapsulamiento
Visión general de los niveles de accesoMétodos Getter y SetterOcultamiento de informaciónLa palabra clave finalResumen - Gestor de cuentas bancarias5Polimorfismo
Fundamentos de sobrecarga de métodosSobrescritura de métodos (tiempo de ejecución)Upcasting y DowncastingEl operador instanceofClases y métodos abstractosResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaAgregación vs. ComposiciónClases internas, anidadas y anónimasEnums y métodos de EnumRecords (Java 16+)Clases selladas (Java 17+)11Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón BuilderPatrón ObserverPatrón Strategy3Propiedades de clase y miembros estáticos
Variables de instancia vs. estáticasMétodos estáticosBloques estáticosConstantes (static final)Repaso - Contador y utilidad6Interfaces y Clases Abstractas
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesMétodos Default y Static en InterfacesClases Abstractas vs InterfacesInterfaces FuncionalesResumen - Sistema de Pagos9Genéricos
Introducción a los genéricosClases genéricasMétodos genéricosParámetros de tipo delimitadosComodines (?, extends, super)Resumen - Contenedor genérico12Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Iterator