Menu
Coddy logo textTech

Erros Checked vs Unchecked

Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 61 de 87.

Você viu que a hierarquia de exceções do Java se divide em diferentes ramos. A distinção fundamental que você precisa entender é entre exceções checked e unchecked—isso afeta como você deve tratá-las em seu código.

Exceções verificadas (Checked exceptions) são exceções que o compilador obriga você a tratar. Elas estendem Exception diretamente (não através de RuntimeException). Você deve capturá-las ou declará-las com throws:

// Deve lidar com IOException - ela é verificada
public void readFile(String path) throws IOException {
    FileReader reader = new FileReader(path);  // Pode lançar IOException
}

// Ou capture-a
public void readFileSafe(String path) {
    try {
        FileReader reader = new FileReader(path);
    } catch (IOException e) {
        System.out.println("File error: " + e.getMessage());
    }
}

Exceções não verificadas estendem RuntimeException. O compilador não exige que você as trate — elas geralmente indicam erros de programação, como referências nulas ou acesso inválido a arrays:

// Nenhuma declaração throws necessária
public int divide(int a, int b) {
    return a / b;  // Pode lançar ArithmeticException (não verificada)
}

String name = null;
name.length();  // NullPointerException (não verificada)

Ao criar exceções personalizadas, escolha a classe pai com base em como você deseja que os chamadores as manipulem. Use exceções verificadas para condições recuperáveis que o chamador deve antecipar. Use exceções não verificadas para erros de programação que não devem ocorrer em um código correto.

challenge icon

Desafio

Fácil

Vamos construir um sistema de verificação de idade que demonstra a principal diferença entre exceções verificadas (checked) e não verificadas (unchecked)! Você criará exceções personalizadas de ambos os tipos e verá como o compilador as trata de forma diferente.

Você organizará seu código em quatro arquivos:

  • InvalidAgeException.java: Crie uma exceção verificada (checked exception) para falhas de validação de idade. Esta exceção deve estender Exception diretamente, o que significa que os chamadores serão forçados a tratá-la. Inclua um construtor que aceite uma mensagem e a passe para a classe pai.
  • NegativeAgeException.java: Crie uma exceção não verificada (unchecked exception) para quando alguém fornecer uma idade negativa (um erro de programação que não deveria acontecer com uma entrada correta). Esta deve estender RuntimeException. Inclua um construtor que aceite e passe uma mensagem para o pai.
  • AgeVerifier.java: Crie uma classe que valide idades usando ambos os tipos de exceção. Inclua dois métodos estáticos:

    verifyAge(int age) - Este método deve lançar NegativeAgeException (não verificada) com a mensagem "Age cannot be negative: " + age se a idade for menor que 0. Se a idade for menor que 18, lance InvalidAgeException (verificada) com a mensagem "Must be 18 or older: " + age. Caso contrário, imprima "Age " + age + " verified successfully". Como este método lança uma exceção verificada, você deve declará-lo com throws InvalidAgeException.

    verifyAgeUncheckedOnly(int age) - Este método usa apenas exceções não verificadas. Se a idade for negativa, lance NegativeAgeException com o mesmo formato de mensagem. Se a idade for menor que 18, lance uma IllegalArgumentException com a mensagem "Too young: " + age. Caso contrário, imprima "Age " + age + " verified (unchecked method)". Note que este método não precisa de declaração throws!

  • Main.java: Reúna seu sistema de verificação! Você receberá uma entrada: uma idade (inteiro).

    Primeiro, imprima "=== Checked Exception Method ===" e chame verifyAge com a idade de entrada. Como ele lança uma exceção verificada, você deve envolvê-lo em um try-catch. Capture InvalidAgeException e imprima "Checked exception caught: " + e.getMessage(). Também capture NegativeAgeException e imprima "Unchecked exception caught: " + e.getMessage().

    Em seguida, imprima uma linha em branco e "=== Unchecked Exception Method ===". Chame verifyAgeUncheckedOnly com a mesma idade. Embora este método possa lançar exceções, você não é forçado a capturá-las. No entanto, envolva-o em um try-catch de qualquer maneira para lidar com os erros graciosamente. Capture NegativeAgeException e imprima "Runtime exception caught: " + e.getMessage(). Capture IllegalArgumentException e imprima "Illegal argument caught: " + e.getMessage().

Você receberá uma entrada: um número inteiro representando a idade a ser verificada.

Observe a diferença fundamental: o método com a exceção verificada exige uma declaração throws e força os chamadores a tratá-la, enquanto o método não verificado compila normalmente sem qualquer tratamento de exceção. Esta é a distinção fundamental entre exceções checked e unchecked em Java!

Folha de consulta

As exceções em Java são divididas em exceções verificadas (checked) e não verificadas (unchecked), o que determina como o compilador impõe o tratamento delas.

Exceções verificadas estendem Exception diretamente (não através de RuntimeException). O compilador obriga você a capturá-las ou declará-las com throws:

// Deve declarar com throws
public void readFile(String path) throws IOException {
    FileReader reader = new FileReader(path);
}

// Ou capturá-la
public void readFileSafe(String path) {
    try {
        FileReader reader = new FileReader(path);
    } catch (IOException e) {
        System.out.println("File error: " + e.getMessage());
    }
}

Exceções não verificadas estendem RuntimeException. O compilador não exige que você as trate. Elas geralmente indicam erros de programação:

// Nenhuma declaração throws é necessária
public int divide(int a, int b) {
    return a / b;  // Pode lançar ArithmeticException (não verificada)
}

String name = null;
name.length();  // NullPointerException (não verificada)

Ao criar exceções personalizadas, escolha a classe pai com base em como os chamadores devem tratá-las:

  • Use exceções verificadas (estenda Exception) para condições recuperáveis que o chamador deve antecipar
  • Use exceções não verificadas (estenda RuntimeException) para erros de programação que não devem ocorrer em um código correto

Experimente você mesmo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int age = scanner.nextInt();
        
        // TODO: Testar o método de exceção verificada (checked exception)
        // Imprimir: "=== Checked Exception Method ==="
        // Chamar AgeVerifier.verifyAge(age) em um try-catch
        // - Catch InvalidAgeException: imprimir "Checked exception caught: [message]"
        // - Catch NegativeAgeException: imprimir "Unchecked exception caught: [message]"
        
        
        // TODO: Imprimir uma linha em branco, depois "=== Unchecked Exception Method ==="
        // Chamar AgeVerifier.verifyAgeUncheckedOnly(age) em um try-catch
        // - Catch NegativeAgeException: imprimir "Runtime exception caught: [message]"
        // - Catch IllegalArgumentException: imprimir "Illegal argument caught: [message]"
        
    }
}
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