Introdução ao tratamento de erros em Java
No mundo da programação, erros são inevitáveis. Eles ocorrem por diversos motivos: entrada incorreta do usuário, indisponibilidade de arquivo, erros na lógica do programa ou falhas na rede. Na linguagem Java, para gerenciar tais situações, existe um mecanismo poderoso e flexível — as exceções (exceptions). O tratamento correto de erros não é apenas uma boa prática, mas a chave para a estabilidade, confiabilidade e segurança da sua aplicação.
Neste artigo, vamos detalhar como funciona o tratamento de erros em Java, começando pela construção básica try/catch e terminando com técnicas avançadas, como try-with-resources e a criação de exceções personalizadas. Você aprenderá a diferença entre exceções verificadas (checked) e não verificadas (unchecked) e como usá-las corretamente.
Fundamentos: a construção try/catch e finally
Bloco try e catch
O coração do tratamento de exceções em Java é a construção try/catch. O código que pode lançar uma exceção é colocado dentro do bloco try. Se uma exceção ocorrer neste bloco, a execução é imediatamente transferida para o bloco catch correspondente, onde a exceção é tratada.
public class Main { public static void main(String[] args) { try { int result = 10 / 0; // Isso causará uma ArithmeticException System.out.println("Resultado: " + result); } catch (ArithmeticException e) { System.out.println("Erro: divisão por zero!"); e.printStackTrace(); // Exibe a pilha de chamadas para depuração } System.out.println("O programa continua em execução..."); }}Observe: a linha System.out.println("Resultado: " + result); não será executada, pois a exceção ocorreu antes. No entanto, o programa não "falhará" — o controle passará para o catch e a execução continuará após o bloco try/catch.
Múltiplos blocos catch
Um único bloco try pode ter vários blocos catch para tratar diferentes tipos de exceções. É importante lembrar que exceções mais específicas devem ser declaradas antes das mais genéricas.
try { String str = null; System.out.println(str.length()); // NullPointerException int[] arr = new int[5]; arr[10] = 100; // ArrayIndexOutOfBoundsException} catch (NullPointerException e) { System.out.println("NullPointerException: " + e.getMessage());} catch (ArrayIndexOutOfBoundsException e) { System.out.println("ArrayIndexOutOfBoundsException: " + e.getMessage());} catch (Exception e) { // Manipulador genérico para todas as outras exceções System.out.println("Erro geral: " + e.getMessage());}Bloco finally
O bloco finally é um bloco especial que é executado sempre, independentemente de uma exceção ter sido lançada ou não. Ele é ideal para liberar recursos: fechar arquivos, conexões de banco de dados ou sockets.
import java.io.*;
public class FileExample { public static void main(String[] args) { FileInputStream file = null; try { file = new FileInputStream("test.txt"); int data = file.read(); System.out.println((char) data); } catch (FileNotFoundException e) { System.out.println("Arquivo não encontrado!"); } catch (IOException e) { System.out.println("Erro de entrada/saída!"); } finally { try { if (file != null) { file.close(); // Fechamos o arquivo em qualquer caso } } catch (IOException e) { System.out.println("Erro ao fechar o arquivo!"); } } }}Mesmo que uma exceção ocorra no bloco try ou catch, o bloco finally será executado. Isso garante que recursos sejam liberados adequadamente.