Jerarquía de clases de excepciones
Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 59 de 87.
El sistema de manejo de excepciones de Java está construido sobre una jerarquía de clases bien organizada con raíz en la clase Throwable. Comprender esta jerarquía le ayuda a capturar y manejar excepciones de manera más efectiva.
En la parte superior se encuentra Throwable, el padre de todas las excepciones y errores. Tiene dos subclases directas:
Throwable
├── Error // Problemas graves (no capturar estos)
└── Exception // Problemas recuperables
└── RuntimeException // Excepciones no verificadasError representa problemas graves que las aplicaciones no deberían intentar manejar—como OutOfMemoryError o StackOverflowError. Estos indican problemas fundamentales con la propia JVM.
Exception es la rama con la que más trabajarás. Se divide en dos categorías: excepciones verificadas (subclases directas de Exception) y excepciones no verificadas (subclases de RuntimeException).
// Clases de excepciones comunes
Exception
├── IOException // Problemas de archivos/red
├── SQLException // Problemas de base de datos
└── RuntimeException
├── NullPointerException
├── ArrayIndexOutOfBoundsException
└── IllegalArgumentExceptionDebido a que las excepciones son clases, siguen las reglas de herencia. Cuando capturas un tipo de excepción padre, también capturas todos sus hijos:
try {
// algún código
} catch (Exception e) {
// Captura TODAS las excepciones (generalmente demasiado amplio)
}try {
// algo de código
} catch (RuntimeException e) {
// Captura solo excepciones de tiempo de ejecución y subclases
}Esta jerarquía te permite ser tan específico o general como sea necesario al manejar errores, y es la base para crear tus propias excepciones personalizadas.
Desafío
Fácil¡Vamos a construir un analizador de excepciones que demuestre cómo funciona la jerarquía de excepciones de Java en la práctica! Crearás un sistema que capture excepciones en diferentes niveles de especificidad e informe qué tipo fue capturado.
Organizarás tu código en tres archivos:
ExceptionThrower.java: Crea una clase que pueda activar diferentes tipos de excepciones según la entrada. Tu clase debe tener tres métodos estáticos:triggerRuntime(String type)- Basado en la cadena de tipo, lanza diferentes excepciones de tiempo de ejecución (runtime exceptions):- Si el tipo es
"null", lanza unaNullPointerExceptioncon el mensaje"Null value encountered" - Si el tipo es
"index", lanza unaArrayIndexOutOfBoundsExceptioncon el mensaje"Invalid index" - Si el tipo es
"argument", lanza unaIllegalArgumentExceptioncon el mensaje"Bad argument"
triggerArithmetic()- Lanza unaArithmeticExceptioncon el mensaje"Division error"triggerGeneric()- Lanza unaRuntimeExceptioncon el mensaje"Generic runtime error"- Si el tipo es
ExceptionAnalyzer.java: Crea una clase que capture excepciones en diferentes niveles de jerarquía e identifique qué fue capturado. Incluye estos métodos estáticos:analyzeSpecific(String type)- Llama aExceptionThrower.triggerRuntime(type)dentro de un bloque try. Usa bloques catch separados paraNullPointerException,ArrayIndexOutOfBoundsExceptioneIllegalArgumentException. Para cada uno, imprime:Caught specific: [exception class simple name]seguido deMessage: [exception message]analyzeWithParent()- Llama aExceptionThrower.triggerArithmetic()dentro de un bloque try. Captúrala usandoRuntimeException(el tipo padre). Imprime:Caught via parent: RuntimeExceptionseguido deActual type: [exception class simple name]analyzeWithGrandparent()- Llama aExceptionThrower.triggerGeneric()dentro de un bloque try. Captúrala usandoException(un nivel aún más alto en la jerarquía). Imprime:Caught via grandparent: Exceptionseguido deActual type: [exception class simple name]Main.java: ¡Une tu analizador de excepciones! Recibirás una entrada: una cadena de tipo de excepción (ya sea"null","index"o"argument").Primero, imprime
=== Specific Catch ===y llama aanalyzeSpecificcon tu entrada.Luego imprime una línea en blanco,
=== Parent Catch ===, y llama aanalyzeWithParent.Finalmente, imprime una línea en blanco,
=== Grandparent Catch ===, y llama aanalyzeWithGrandparent.
Recibirás una entrada: el tipo de excepción a activar ("null", "index" o "argument").
Usa e.getClass().getSimpleName() para obtener el nombre de la clase de la excepción y e.getMessage() para recuperar su mensaje. ¡Este desafío muestra cómo capturar un tipo de excepción padre también captura a todos sus hijos, un concepto clave al decidir qué tan específico debe ser tu manejo de excepciones!
Hoja de referencia
El manejo de excepciones de Java se basa en una jerarquía de clases con raíz en Throwable:
Throwable
├── Error // Problemas graves (no capturar)
└── Exception // Problemas recuperables
└── RuntimeException // Excepciones no verificadasError representa problemas graves de la JVM como OutOfMemoryError o StackOverflowError que las aplicaciones no deberían manejar.
Exception se divide en excepciones verificadas (subclases directas) y excepciones no verificadas (subclases de RuntimeException):
Exception
├── IOException // Problemas de archivos/red
├── SQLException // Problemas de base de datos
└── RuntimeException
├── NullPointerException
├── ArrayIndexOutOfBoundsException
└── IllegalArgumentExceptionCapturar un tipo de excepción padre también captura a todos sus hijos:
try {
// algo de código
} catch (Exception e) {
// Captura TODAS las excepciones
}
try {
// algo de código
} catch (RuntimeException e) {
// Captura solo excepciones de tiempo de ejecución y subclases
}Use e.getClass().getSimpleName() para obtener el nombre de la clase de la excepción y e.getMessage() para recuperar su mensaje.
Pruébalo tú mismo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String type = scanner.nextLine();
// TODO: Imprimir "=== Specific Catch ===" y llamar a ExceptionAnalyzer.analyzeSpecific(type)
// TODO: Imprimir una línea en blanco, luego "=== Parent Catch ===", luego llamar a ExceptionAnalyzer.analyzeWithParent()
// TODO: Imprimir una línea en blanco, luego "=== Grandparent Catch ===", luego llamar a ExceptionAnalyzer.analyzeWithGrandparent()
}
}
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