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

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

Como exceptions são classes, elas seguem as regras de herança. Quando você faz catch de um tipo de exception pai, 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) {
    // 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 exception que demonstra como a hierarquia de exceptions do Java funciona na prática! Você criará um sistema que captura exceptions 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 que possa disparar diferentes tipos de exceptions com base na entrada. Sua classe deve ter três métodos estáticos:

    triggerRuntime(String type) - Com base na string de tipo, dispare diferentes exceptions de tempo de execução:

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

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

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

  • ExceptionAnalyzer.java: Crie uma classe que capture exceptions 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-o 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-o usando Exception (ainda mais acima na hierarquia). Imprima: Caught via grandparent: Exception seguido de Actual type: [exception class simple name]

  • Main.java: Reúna seu analisador de exceptions! Você receberá uma entrada: uma string de tipo de exception (que 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 exception a ser disparado ("null", "index" ou "argument").

Use e.getClass().getSimpleName() para obter o nome da classe da exception e e.getMessage() para recuperar sua mensagem. Este desafio mostra como capturar um tipo de exception pai também captura todos os seus filhos: um conceito fundamental ao decidir o nível de especificidade do tratamento de suas exceptions!

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