Menu
Coddy logo textTech

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 é baseado em uma hierarquia de classes bem organizada, cuja raiz é a classe Throwable. Compreender essa hierarquia ajuda você a capturar e tratar exceções com mais eficácia.

No topo está Throwable, a classe pai de todas as exceções e erros. Ela tem duas subclasses diretas:

Throwable
├── Error          // Problemas sérios (não capture estes)
└── Exception      // Problemas recuperáveis
    └── RuntimeException  // Exceções não verificadas

Erro representa problemas graves que as aplicações não devem tentar tratar, como OutOfMemoryError ou StackOverflowError. Eles indicam problemas fundamentais na 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
    └── IllegalArgumentException

Como as exceções são classes, elas seguem as regras de herança. Quando você captura um tipo de exceção pai, também captura todos os seus tipos derivados:

try {
    // algum código
} catch (Exception e) {
    // Captura TODAS as exceções (geralmente amplo demais)
}
try {
    // algum código
} catch (RuntimeException e) {
    // Catches only runtime exceptions and subclasses
}

Essa hierarquia permite que você seja tão específico ou geral quanto necessário ao lidar com erros e é a base para criar suas próprias exceções personalizadas.

challenge icon

Desafio

Fácil

Vamos criar 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 informa qual tipo foi capturado.

Você organizará seu código em três arquivos:

  • ExceptionThrower.java: Crie uma classe capaz de 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 do tipo, lance diferentes exceções de tempo de execução:

    • Se type for "null", lance uma NullPointerException com a mensagem "Null value encountered"
    • Se type for "index", lance uma ArrayIndexOutOfBoundsException com a mensagem "Invalid index"
    • Se type for "argument", lance uma IllegalArgumentException com a mensagem "Bad argument"

    triggerArithmetic() - Lance uma ArithmeticException com a mensagem "Division error"

    triggerGeneric() - Lance uma IllegalStateException com a mensagem "Generic runtime error" (sua hierarquia é Exception > RuntimeException > IllegalStateException)

  • 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) - Chame ExceptionThrower.triggerRuntime(type) dentro de um bloco try. Use blocos catch separados para NullPointerException, ArrayIndexOutOfBoundsException e IllegalArgumentException. Para cada um, imprima: Caught specific: [exception class simple name], seguido de Message: [exception message]

    analyzeWithParent() - Chame ExceptionThrower.triggerArithmetic() dentro de um bloco try. Capture-a usando RuntimeException (o tipo pai). Imprima: Caught via parent: RuntimeException, seguido de Actual type: [exception class simple name]

    analyzeWithGrandparent() - Chame ExceptionThrower.triggerGeneric() dentro de um bloco try. Capture-a usando Exception (um nível ainda mais alto na hierarquia). Imprima: Caught via grandparent: Exception, seguido de Actual type: [exception class simple name]

  • Main.java: Reúna seu analisador de exceções! Você receberá uma entrada: uma string que representa o tipo de exceção (pode ser "null", "index" ou "argument").

    Primeiro, imprima === Specific Catch === e chame analyzeSpecific com sua entrada.

    Em seguida, imprima uma linha em branco, === Parent Catch === e chame analyzeWithParent.

    Por fim, imprima uma linha em branco, === Grandparent Catch === e chame analyzeWithGrandparent.

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 tipos filhos: um conceito fundamental ao decidir o nível de especificidade do tratamento de exceções!

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: Print "=== Specific Catch ===" and call ExceptionAnalyzer.analyzeSpecific(type)
        
        // TODO: Imprima uma linha em branco, depois "=== Parent Catch ===", depois chame ExceptionAnalyzer.analyzeWithParent()
        
        // TODO: Print a blank line, then "=== Grandparent Catch ===", then call ExceptionAnalyzer.analyzeWithGrandparent()
    }
}
quiz iconTeste seus conhecimentos

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

Pratique por conta própria: Compilador de Java online