CodeGym /Cursos /JAVA 25 SELF /finally e throw: finalização e geração de exceções

finally e throw: finalização e geração de exceções

JAVA 25 SELF
Nível 11 , Lição 3
Disponível

1. Introdução ao bloco finally

Quando você trabalha com recursos — arquivos, conexões de rede, bancos de dados — é importante garantir que eles serão fechados ou liberados sempre, mesmo que ocorra um erro durante a execução. Em Java há um bloco específico para isso — finally.

Como o finally funciona?

O bloco finally é parte da construção try-catch-finally. O código dentro de finally é sempre executado (se ele está presente) — independentemente de ter havido exceção ou não. Mesmo que em try haja um return ou uma exceção seja lançada — finally ainda assim será executado (a menos que o computador seja desligado ou que o programa seja encerrado à força via System.exit(0)).

Sintaxe:

try {
    // Código onde uma exceção pode ocorrer
} catch (ExceptionType e) {
    // Tratamento do erro
} finally {
    // Este código sempre será executado!
}

Exemplo

try {
    System.out.println("Início da execução");
    int result = 10 / 0; // aqui ocorrerá um erro
    System.out.println("Resultado: " + result);
} catch (ArithmeticException e) {
    System.out.println("Erro: divisão por zero");
} finally {
    System.out.println("Este código será executado de qualquer forma");
}

Resultado da execução:

Início da execução
Erro: divisão por zero
Este código será executado de qualquer forma

O que está acontecendo?

  1. No try tentamos dividir dois números e obtemos um erro.
  2. Se ocorrer um erro na divisão — o catch irá tratá-lo.
  3. Mas! Em qualquer caso, finally será executado e escreverá uma mensagem no console.

2. finally sem catch

Podem existir 3 variantes da construção:

  • Completa: try-catch-finally
  • Sem finally: try-catch
  • Sem catch: try-finally

A terceira variante é usada quando quem irá capturar e tratar o erro é um método em um nível acima. Mas o bloco finally é necessário para garantir a execução de determinado código:

  • Fechamento de arquivos, conexões de rede, bancos de dados.
  • Liberação de quaisquer recursos (por exemplo, locks).
  • Registro em log: gravação de informações sobre a conclusão da operação.

Exemplo:

try {
    System.out.println("Dividindo números");
    int result = 10 / 0;   // erro!
    System.out.println("Resultado: " + result);
} finally {
    System.out.println("Bloco finally executado");
}

Resultado:

Dividindo números
Bloco finally executado
Exception in thread "main" java.lang.ArithmeticException: / by zero

Quando o finally NÃO é executado?

Quase sempre é executado. As exceções são quando:

  1. O programa é encerrado à força por meio de: System.exit(0).
  2. A thread onde o finally está sendo executado é “morta” à força.
  3. O computador é desligado.

3. Operador throw: como gerar uma exceção manualmente

Às vezes o próprio Java “lança” exceções (por exemplo, divisão por zero, acesso fora dos limites de um array). Mas há situações em que você quer declarar explicitamente: “Isso é um erro! Não posso continuar a execução!”. Para isso, o Java possui o operador throw.

Analogia: Se você está em uma loja e vê um produto vencido — você “lança” uma reclamação. Da mesma forma no código: se algo está errado — você lança uma exceção.

Sintaxe de throw

throw new ExceptionType("Mensagem de erro");

ExceptionType é qualquer classe que herde de Throwable (geralmente Exception ou RuntimeException). Entre parênteses vai a mensagem que ajuda a entender o que deu errado.

Exemplo: validação de argumentos do método

public static int safeDivide(int a, int b) {
    if (b == 0) {
        throw new IllegalArgumentException("O divisor não pode ser igual a zero");
    }
    return a / b;
}

Uso:

public static void main(String[] args) {
    try {
        int result = safeDivide(10, 0);
        System.out.println("Resultado: " + result);
    } catch (IllegalArgumentException e) {
        System.out.println("Erro: " + e.getMessage());
    }
}

Resultado:

Erro: O divisor não pode ser igual a zero

Quando usar throw?

  • Validação de argumentos do método (por exemplo, se veio null ou dados inválidos).
  • Verificação do estado do objeto (por exemplo, tentar sacar dinheiro de uma conta com 0 euros).
  • Dentro de catch — quando você quer “relançar” a exceção adiante (por exemplo, adicionando informação adicional).

4. Combinando try-catch-finally e throw

Às vezes essas construções trabalham juntas. Por exemplo, você captura um erro, mas depois decide lançar outro, mais informativo.

public static int parseAndDivide(String text, int divisor) {
    try {
        int number = Integer.parseInt(text);
        if (divisor == 0) {
            throw new IllegalArgumentException("O divisor não pode ser igual a zero");
        }
        return number / divisor;
    } catch (NumberFormatException e) {
        throw new IllegalArgumentException("A string '" + text + "' não é um número");
    } finally {
        System.out.println("Tentativa de processar a string: " + text);
    }
}

Uso:

try {
    int result = parseAndDivide("42a", 2);
    System.out.println("Resultado: " + result);
} catch (IllegalArgumentException e) {
    System.out.println("Erro: " + e.getMessage());
}

Resultado:

Tentativa de processar a string: 42a
Erro: A string '42a' não é um número

Um detalhe importante: return e finally

Mesmo que haja um return no bloco try, o finally ainda será executado!

public static int getValue() {
    try {
        return 10;
    } finally {
        System.out.println("o finally ainda será executado!");
    }
}

A chamada getValue() exibirá:

o finally ainda será executado!

5. Erros comuns ao usar finally e throw

Erro nº 1: esqueceu de fechar o recurso sem finally.
Problema muito comum: abriu um arquivo, não o fechou — gerou vazamento de recursos. Sempre use finally (ou try-with-resources, sobre o qual falaremos depois).

Erro nº 2: lançou uma exceção, mas não a tratou.
Se você lança uma exceção com throw, mas não a captura em lugar nenhum (não há try-catch), o programa terminará de forma abrupta. Sempre pense em quem irá capturar sua exceção.

Erro nº 3: return dentro de finally.
Se por engano você escrever um return dentro de finally, ele irá “sobrepor” todos os return ou throw anteriores. Isso pode levar a bugs muito difíceis de detectar. Não é recomendado de forma alguma!

public int tricky() {
    try {
        return 1;
    } finally {
        return 2; // PERIGOSO: retornará 2, e não 1!
    }
}

Resultado: será retornado 2, embora no try fosse 1.

Erro nº 4: perda de informação sobre a exceção.
Se você captura uma exceção e, em seguida, lança outra sem preservar a informação da anterior (e), você perde a stack trace, o que dificulta a depuração. É melhor escrever assim:

catch (NumberFormatException e) {
    throw new IllegalArgumentException("Erro de conversão", e);
}
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION