Todo programa encontra situações inesperadas: arquivo que não existe, conexão que cai, usuário que digita letras onde deveria ter número, divisão por zero. Lidar com esses erros de forma elegante é o que separa um software amador de um profissional. Java tem um dos sistemas de tratamento de exceções mais completos entre as linguagens populares, e entendê-lo é obrigatório para qualquer desenvolvedor Java.
O que é uma exceção?
Uma exceção é um evento que interrompe o fluxo normal de execução do programa. Quando algo dá errado, o Java cria um objeto de exceção com informações sobre o erro e o “lança” (throws). Se nenhum código tratar essa exceção, ela sobe pela pilha de chamadas até chegar ao topo e terminar o programa com uma mensagem de erro — a famosa stack trace no console, que parece assustadora mas é extremamente útil para debugar.
Exceções em Java formam uma hierarquia. No topo está Throwable, que se divide em Error (problemas sérios da JVM, que normalmente você não trata, como OutOfMemoryError) e Exception (situações que seu código pode e deve tratar). Exception se divide em checked exceptions (o compilador exige que você trate ou declare) e unchecked exceptions (subclasses de RuntimeException, opcionais de tratar).
try-catch: capturando exceções
O bloco try envolve o código que pode lançar exceção. O bloco catch captura e trata a exceção caso ocorra. Se uma linha dentro do try lança exceção, a execução pula imediatamente para o catch correspondente — as linhas restantes do try são ignoradas. Você pode ter múltiplos blocos catch para tipos diferentes de exceção: primeiro os mais específicos, depois os mais genéricos.
Dentro do catch, o objeto de exceção (por convenção chamado e) tem métodos úteis: e.getMessage() retorna a mensagem de erro, e.printStackTrace() imprime a stack trace completa no console (ótimo para debug), e e.getClass().getSimpleName() retorna o nome da exceção. Em produção, use um logger (Log4j, SLF4J) em vez de System.out ou e.printStackTrace() diretamente.
O bloco finally
O bloco finally executa sempre — seja o código executado com sucesso, seja uma exceção lançada e capturada, seja uma exceção não capturada. É o lugar certo para liberar recursos: fechar conexões de banco de dados, fechar arquivos abertos, encerrar streams. Esquecer de fechar recursos é uma causa comum de memory leaks e “connection pool exhausted” em aplicações Java.
Java 7 introduziu o try-with-resources: se o recurso implementa AutoCloseable (como FileReader, Connection, InputStream), você o declara no parênteses do try e ele é fechado automaticamente ao sair do bloco — com ou sem exceção. É a forma moderna e preferida de gerenciar recursos, eliminando o finally com close manual.
Lançando exceções com throw
Você pode lançar exceções manualmente com throw new TipoDeExcecao("mensagem"). Isso é útil para validações de negócio: se um método sacar recebe valor negativo, throw new IllegalArgumentException("Valor de saque não pode ser negativo") comunica claramente o problema. O método que pode lançar checked exceptions deve declarar isso na assinatura com throws NomeDaExcecao — avisando quem o chamar que precisa tratar.
Criando suas próprias exceções
Criar exceções customizadas torna o código muito mais expressivo. Uma exceção SaldoInsuficienteException é muito mais clara que uma genérica RuntimeException. Para criar, basta estender RuntimeException (unchecked) ou Exception (checked) e adicionar um construtor que passa a mensagem para o super. Adicione atributos extras se quiser carregar contexto: o valor tentado, o saldo atual, etc.
A regra prática para quando criar exceção customizada versus usar as do Java: se existe uma exceção da biblioteca padrão que descreve exatamente a situação (IllegalArgumentException para argumento inválido, IllegalStateException para estado inválido do objeto), use ela. Se seu domínio de negócio tem erros específicos que não têm equivalente nas exceções padrão, crie as suas. Boas mensagens de exceção economizam horas de debug: inclua o valor que causou o problema, o contexto, e o que seria válido. “Valor inválido” é inútil; “Valor -50.00 inválido: saque deve ser positivo e menor que o saldo R$ 100.00” é diagnóstico completo.
Tem um projeto em mente?
Somos especialistas em transformar ideias em produtos digitais. Apps, sites, automações e IA — vamos construir juntos.