No ecossistema Java, erros são inevitáveis. Seja uma conexão de rede que falha, um arquivo inexistente ou um cálculo matemático impossível, sua aplicação precisa saber como reagir. O tratamento de exceções não serve apenas para "não deixar o programa travar"; é uma ferramenta de design de software que garante a resiliência e a manutenibilidade do sistema.
Neste guia, vamos explorar desde a hierarquia básica até a criação de exceções personalizadas, focando em boas práticas que separam os amadores dos especialistas.
1. A Hierarquia das Exceções: Onde Tudo Começa
Para dominar o tratamento de erros, você deve entender que em Java, tudo o que pode ser "lançado" (thrown) deriva da classe Throwable. Dela, surgem dois ramos principais:
Error: Problemas graves que a aplicação normalmente não consegue recuperar (ex:
OutOfMemoryError,StackOverflowError). Você não deve tentar capturar esses erros.Exception: Condições que um programa deve capturar e tratar.
Exceções verificadas versus exceções não verificadas
A distinção mais importante no Java é entre exceções verificadas e não verificadas.
Exceções Verificadas (Checked)
São aquelas que o compilador obriga você a tratar ou declarar. Elas representam condições fora do controle direto do programa (como problemas de I/O).
Exemplos:
IOException,SQLException,ClassNotFoundException.Regra: Se um método lança uma Checked Exception, você deve usar um bloco
try-catchou declararthrowsna assinatura do método.
Exceções Não Verificadas (Unchecked)
Também conhecidas como RuntimeException. Elas geralmente indicam erros de lógica do programador.
Exemplos:
NullPointerException,ArrayIndexOutOfBoundsException,ArithmeticException.Regra: O compilador não exige o tratamento. O ideal é prevenir essas exceções com validações (ex: verificar se um objeto é nulo antes de usá-lo) em vez de apenas capturá-las.
2. O Mecanismo de Controle: Try, Catch, Finally e o Moderno Try-with-Resources
O bloco try-catch é a unidade básica de tratamento.

Try-with-Resources
A partir do Java 7, para objetos que implementam AutoCloseable (como conexões de banco ou leitores de arquivo), usamos o Try-with-Resources. Isso garante que o recurso será fechado automaticamente, evitando vazamentos de memória (memory leaks).

3. Boas Práticas: O Que Fazer e O Que Evitar
Tratar exceções incorretamente pode ser pior do que não tratá-las. Aqui estão as regras de ouro:
Jamais deixe o bloco Catch vazio
O erro mais comum é "engolir" a exceção:

Se algo der errado, você nunca saberá. No mínimo, registre o erro em um log (usando Log4j ou SLF4J).
Capture a exceção mais específica primeiro
Sempre organize seus catch do mais específico para o mais genérico. Se você capturar Exception primeiro, os blocos subsequentes para IOException nunca serão alcançados.
Não use Exceções para Controle de Fluxo
Exceções são caras para a JVM (exigem o preenchimento da stack trace). Não use um try-catch para verificar se um usuário existe; use um simples if/else.
4. Criando Exceções Personalizadas (Custom Exceptions)
Por que criar sua própria exceção se o Java já tem centenas? A resposta é:Semântica.
Ao criar SaldoInsuficienteException, você torna o erro claro para quem lê o código, em vez de lançar uma genérica RuntimeException.
Passo a passo para criar uma:
Escolha a base: Estenda
Exception(se quiser que seja obrigatória) ouRuntimeException(se quiser que seja opcional). A tendência moderna é preferirRuntimeExceptionpara evitar poluição visual no código.Defina os construtores: Geralmente passamos a mensagem de erro para a superclasse.


5. Lançando vs. Propagando (Throw vs. Throws)
Existe uma confusão comum entre estas duas palavras-chave:
throw: Usado dentro do corpo do método para lançar uma instância de exceção.throws: Usado na assinatura do método para avisar que aquele método pode lançar uma exceção, delegando a responsabilidade de tratamento para quem chamar o método.
6. O Padrão Global de Tratamento (Global Exception Handling)
Em aplicações modernas, como as construídas com Spring Boot, evitamos encher as classes de negócio com try-catch. Utilizamos o padrão @ControllerAdvice. Isso centraliza o tratamento de erros em um único lugar, onde capturamos as exceções personalizadas e as transformamos em respostas HTTP amigáveis (JSON) para o cliente.
Exemplo de fluxo ideal:
A camada de Serviço valida uma regra e lança uma
NegocioException.O Handler Global intercepta essa exceção.
O sistema retorna um
400 Bad Requestcom uma mensagem clara: "Seu saldo é insuficiente".
Tratar exceções em Java evoluiu de uma simples estrutura de controle para uma parte essencial da arquitetura limpa. Entender a hierarquia entre Checked e Unchecked, evitar blocos catch vazios e saber quando criar exceções personalizadas são passos cruciais para qualquer desenvolvedor que deseja entregar software de qualidade industrial.
Lembre-se: o objetivo não é apenas evitar que o código quebre, mas garantir que, quando ele quebrar, ele o faça de forma graciosa, fornecendo informações úteis para o desenvolvedor e para o usuário.

Comentários
Postar um comentário