Hierarquia de Classes de Exceção
Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 59 de 87.
O sistema de tratamento de exceções do Java é construído sobre uma hierarquia de classes bem organizada enraizada na classe Throwable. Entender essa hierarquia ajuda você a capturar e tratar exceções de forma mais eficaz.
No topo está o Throwable, o pai de todas as exceções e erros. Ele possui duas subclasses diretas:
Throwable
├── Error // Problemas sérios (não capture estes)
└── Exception // Problemas recuperáveis
└── RuntimeException // Exceções não verificadasError representa problemas sérios que as aplicações não devem tentar tratar — como OutOfMemoryError ou StackOverflowError. Estes indicam problemas fundamentais com a própria JVM.
Exception é o ramo com o qual você mais trabalhará. Ele se divide em duas categorias: exceções verificadas (subclasses diretas de Exception) e exceções não verificadas (subclasses de RuntimeException).
// Classes de exceção comuns
Exception
├── IOException // Problemas de arquivo/rede
├── SQLException // Problemas de banco de dados
└── RuntimeException
├── NullPointerException
├── ArrayIndexOutOfBoundsException
└── IllegalArgumentExceptionComo as exceções são classes, elas seguem as regras de herança. Quando você captura um tipo de exceção pai, você também captura todos os seus filhos:
try {
// algum código
} catch (Exception e) {
// Captura TODAS as exceções (geralmente amplo demais)
}try {
// algum código
} catch (RuntimeException e) {
// Captura apenas exceções de tempo de execução e subclasses
}Esta hierarquia permite que você seja tão específico ou geral quanto necessário ao tratar erros, e é a base para criar suas próprias exceções personalizadas.
Desafio
FácilVamos construir um analisador de exceções que demonstra como a hierarquia de exceções do Java funciona na prática! Você criará um sistema que captura exceções em diferentes níveis de especificidade e relata qual tipo foi capturado.
Você organizará seu código em três arquivos:
ExceptionThrower.java: Crie uma classe que possa disparar diferentes tipos de exceções com base na entrada. Sua classe deve ter três métodos estáticos:triggerRuntime(String type)- Com base na string de tipo, lance diferentes exceções de tempo de execução (runtime exceptions):- Se o tipo for
"null", lance umaNullPointerExceptioncom a mensagem"Null value encountered" - Se o tipo for
"index", lance umaArrayIndexOutOfBoundsExceptioncom a mensagem"Invalid index" - Se o tipo for
"argument", lance umaIllegalArgumentExceptioncom a mensagem"Bad argument"
triggerArithmetic()- Lance umaArithmeticExceptioncom a mensagem"Division error"triggerGeneric()- Lance umaRuntimeExceptioncom a mensagem"Generic runtime error"- Se o tipo for
ExceptionAnalyzer.java: Crie uma classe que capture exceções em diferentes níveis da hierarquia e identifique o que foi capturado. Inclua estes métodos estáticos:analyzeSpecific(String type)- ChameExceptionThrower.triggerRuntime(type)dentro de um bloco try. Use blocos catch separados paraNullPointerException,ArrayIndexOutOfBoundsExceptioneIllegalArgumentException. Para cada um, imprima:Caught specific: [exception class simple name]seguido porMessage: [exception message]analyzeWithParent()- ChameExceptionThrower.triggerArithmetic()dentro de um bloco try. Capture-a usandoRuntimeException(o tipo pai). Imprima:Caught via parent: RuntimeExceptionseguido porActual type: [exception class simple name]analyzeWithGrandparent()- ChameExceptionThrower.triggerGeneric()dentro de um bloco try. Capture-a usandoException(ainda mais alto na hierarquia). Imprima:Caught via grandparent: Exceptionseguido porActual type: [exception class simple name]Main.java: Reúna seu analisador de exceções! Você receberá uma entrada: uma string de tipo de exceção (seja"null","index"ou"argument").Primeiro, imprima
=== Specific Catch ===e chameanalyzeSpecificcom sua entrada.Depois, imprima uma linha em branco,
=== Parent Catch ===, e chameanalyzeWithParent.Finalmente, imprima uma linha em branco,
=== Grandparent Catch ===, e chameanalyzeWithGrandparent.
Você receberá uma entrada: o tipo de exceção a ser disparado ("null", "index" ou "argument").
Use e.getClass().getSimpleName() para obter o nome da classe da exceção e e.getMessage() para recuperar sua mensagem. Este desafio mostra como capturar um tipo de exceção pai também captura todos os seus filhos — um conceito fundamental ao decidir quão específico deve ser o seu tratamento de exceções!
Folha de consulta
O tratamento de exceções do Java é construído sobre uma hierarquia de classes enraizada em Throwable:
Throwable
├── Error // Problemas sérios (não capture)
└── Exception // Problemas recuperáveis
└── RuntimeException // Exceções não verificadasError representa problemas sérios da JVM, como OutOfMemoryError ou StackOverflowError, que as aplicações não devem tratar.
Exception divide-se em exceções verificadas (subclasses diretas) e exceções não verificadas (subclasses de RuntimeException):
Exception
├── IOException // Problemas de arquivo/rede
├── SQLException // Problemas de banco de dados
└── RuntimeException
├── NullPointerException
├── ArrayIndexOutOfBoundsException
└── IllegalArgumentExceptionCapturar um tipo de exceção pai também captura todos os seus filhos:
try {
// algum código
} catch (Exception e) {
// Captura TODAS as exceções
}
try {
// algum código
} catch (RuntimeException e) {
// Captura apenas exceções de tempo de execução e subclasses
}Use e.getClass().getSimpleName() para obter o nome da classe da exceção e e.getMessage() para recuperar sua mensagem.
Experimente você mesmo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String type = scanner.nextLine();
// TODO: Imprima "=== Specific Catch ===" e chame ExceptionAnalyzer.analyzeSpecific(type)
// TODO: Imprima uma linha em branco, depois "=== Parent Catch ===", depois chame ExceptionAnalyzer.analyzeWithParent()
// TODO: Imprima uma linha em branco, depois "=== Grandparent Catch ===", depois chame ExceptionAnalyzer.analyzeWithGrandparent()
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosCampos (Atributos)Método ConstrutorSobrecarga de ConstrutorRecapitulação - Calculadora Simples4Herança
Herança Básica (extends)A Palavra-chave superSobrescrita de Método (@Override)Encadeamento de ConstrutoresA Classe ObjectHerança Simples e MultinívelPor que não há Herança Múltipla de ClassesRecapitulação - Hierarquia de Funcionários7Métodos Especiais e a Classe Object
Método toString()equals() e hashCode()Método clone()compareTo() e ComparableInterface ComparatorRecapitulação - Ordenação Personalizada10Tratamento de Exceções em POO
Hierarquia de Classes de ExceçãoExceções PersonalizadasErros Checked vs UncheckedPadrão Try With ResourcesRecapitulação - Usuário Validado2Modificadores de Acesso e Encapsulamento
Visão Geral dos Níveis de AcessoMétodos Getter e SetterOcultação de InformaçõesA Palavra-chave finalRecapitulação - Gerenciador de Conta Bancária5Polimorfismo
Fundamentos de Sobrecarga de MétodosSobrescrita de Métodos (Tempo de Execução)Upcasting e DowncastingO Operador instanceofClasses e Métodos AbstratosRecapitulação - Calculadora de Formas8Conceitos Avançados de OOP
Composição vs HerançaAgregação vs ComposiçãoClasses Internas, Aninhadas e AnônimasEnums e Métodos de EnumRecords (Java 16+)Classes Seladas (Java 17+)11Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão BuilderPadrão ObserverPadrão Strategy3Propriedades de Classe e Membros Estáticos
Variáveis de Instância vs EstáticasMétodos EstáticosBlocos EstáticosConstantes (static final)Recapitulação - Contador e Utilitário6Interfaces e Classes Abstratas
Introdução às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesDefault e Static em InterfacesClasses Abstratas vs InterfacesInterfaces FuncionaisRecapitulação - Sistema de Pagamento9Generics
Introdução a GenericsClasses GenéricasMétodos GenéricosParâmetros de Tipos DelimitadosWildcards (?, extends, super)Recapitulação - Container Genérico12Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Iterator