programandoai

try/catch/finally e throw

Todo programa de verdade encontra o inesperado: uma API fora do ar, um dado no formato errado, uma conta que não deveria acontecer. try/catch é como você diz ao JavaScript: tente isto, mas se der errado, não quebre tudo, me avise.

Estudar esta lição interativa →

Você já usou try/catch de relance, lá no fetch do Módulo 8, para lidar com uma API que podia estar fora do ar. Chegou a hora de entender essa ferramenta com profundidade, porque ela é a espinha dorsal de qualquer programa que precisa continuar funcionando mesmo quando algo dá errado. Pense numa função que calcula o frete de uma entrega: e se o CEP digitado for inválido? E se a API de frete não responder? Sem tratamento de erro, um problema desses derruba o programa inteiro. Com try/catch, você isola o risco.

A estrutura tem três partes, e cada uma tem um papel bem definido: o try ("tente") envolve o código que pode falhar; o catch ("capture") só roda se algo dentro do try der errado, e recebe o erro capturado; e o finally ("finalmente") roda sempre, tenha dado erro ou não, ótimo para uma limpeza que precisa acontecer de qualquer jeito (fechar uma conexão, esconder um "carregando").

// Um erro que o próprio JavaScript lança: ler um JSON quebrado.
function lerConfiguracao(texto) {
  try {
    const dados = JSON.parse(texto);
    console.log("lido:", dados.tema);
  } catch (erro) {
    console.log("Capturado:", erro.name);
  } finally {
    console.log("Isto roda sempre, com erro ou sem erro.");
  }
}

lerConfiguracao('{"tema": "escuro"}'); // dá certo: o catch não roda
lerConfiguracao('{ tema: escuro');     // dá errado: o catch captura o erro

Só que um erro precisa existir para ser capturado, e nem todo erro acontece sozinho: às vezes é você quem detecta que algo está errado com a lógica do seu programa (um valor fora do esperado, uma regra de negócio violada) e precisa avisar o resto do código disso. Para isso existe o throw ("lançar"). Ele cria um objeto de erro (o mais comum é new Error("mensagem explicando o que houve")) e interrompe a execução na hora, saltando direto para o catch mais próximo que estiver "escutando" aquele trecho:

function dividir(a, b) {
  if (b === 0) {
    throw new Error("Não é possível dividir por zero");
  }
  return a / b;
}

try {
  console.log(dividir(10, 2));  // roda normalmente
  console.log(dividir(5, 0));   // lança o erro, pula o resto do try
  console.log("esta linha nunca roda");
} catch (erro) {
  console.log("Capturado:", erro.message);
}

Rode: o throw interrompe o try, e a última linha dele nunca roda.

Repare que o objeto capturado no catch tem propriedades úteis: .message traz a mensagem que você escreveu, e .name traz o "tipo" do erro (por padrão, "Error"). E, unindo com o que você aprendeu no módulo passado sobre extends, dá para criar erros customizados, com um nome próprio, estendendo a classe Error nativa. Isso deixa o catch capaz de distinguir "este erro é de validação" de "este erro é outra coisa", tratando cada tipo do jeito certo:

// Uma classe de erro customizada, estendendo Error (Módulo 12: extends/super).
class ErroDeValidacao extends Error {
  constructor(mensagem) {
    super(mensagem);
    this.name = "ErroDeValidacao";
  }
}

function validarIdade(idade) {
  if (idade < 0) {
    throw new ErroDeValidacao("idade não pode ser negativa");
  }
  return idade;
}

try {
  validarIdade(-5);
} catch (erro) {
  console.log(erro.name + ":", erro.message);
  console.log("é um ErroDeValidacao?", erro instanceof ErroDeValidacao);
}

Erro customizado: o catch lê o name e confere o tipo com instanceof.

Catch genérico demais esconde bugs

Um catch (erro) { } vazio, ou que só faz console.log("deu erro") sem olhar o que realmente aconteceu, é uma armadilha: ele engole qualquer problema, inclusive erros de programação de verdade (um typo, uma variável errada) que você preferia descobrir na hora, não escondidos atrás de um catch silencioso. Bom hábito: sempre que possível, olhe erro.message (ou erro.name, para erros customizados) e decida uma reação específica, em vez de um "engula e siga" genérico.

// Sua vez! Complete validarNota e trate o erro.
function validarNota(nota) {
  // se nota < 0 ou nota > 10, lance: throw new Error("Nota fora do intervalo 0-10");
  // senão, retorne a própria nota
}

try {
  console.log(validarNota(15));
} catch (erro) {
  console.log("Erro:", erro.message);
}

Complete a validação e clique em Rodar.

← Voltar ao índice do curso