try...catch

As declarações try...catch marcam um bloco de declarações para testar (try), e especifica uma resposta, caso uma exceção seja lançada.

Sintaxe

try {
   try_statements
}
[catch (exception_var_1 if condition_1) {
   catch_statements_1
}]
...
[catch (exception_var_2) {
   catch_statements_2
}]
[finally {
   finally_statements
}]
try_statements

Declarações (statements) a serem executadas.

catch_statements_1, catch_statements_2

Declarações que são executadas se uma exceção é lançada no bloco try.

exception_var_1, exception_var_2

Um indentificador que leva um objeto exceção para uma cláusula catch associada.

condition_1

Uma expressão condicional.

finally_statements

Declarações que são executadas depois que a declaração try é completada. Essas declarações são executadas independetemente se uma exceção foi ou não lançada ou capturada.

Descrição

A declaração try consiste em um bloco try, que contém uma ou mais declarações, e ao menos uma cláusula catch ou uma cláusula finally, ou ambas. Ou seja, há 3 formas de declarações try :

  1. try...catch
  2. try...finally
  3. try...catch...finally

Uma cláusula catch contém declarações que especificam o que fazer caso uma exceção seja lançada no bloco try. Ou seja, se você quer que o bloco try tenha êxito, e caso não tenha, você quer que o controle passe para o bloco catch. Caso qualquer declaração dentro do bloco try (ou em uma função chamada no interior do bloco try) lançar uma exceção o controle imediatamente muda para a cláusula catch. Se nenhuma exceção for lançada no bloco try a cláusula catch é ignorada.

A cláusula finally é executada após a excecução do bloco try e da(s) cláusula(s) catch porém antes das declarações seguintes ao try. Ela sempre é executada, independente se uma exceção for lançada ou capturada.

Você pode aninhar uma ou mais declarações try. Caso uma declaração try interior não tenha uma cláusula catch, a cláusula catch pertencente a declaração try que a envolve é introduzida.

Você pode usar a declaração try para manipular exceções em JavaScript. Veja o Guia Javascript para informações sobre exceções em JavaScript.

Cláusula catch incondicional

Quando uma única, incondicional cláusula catch é utilizada, o bloco catch é inserido quando qualquer exceção for lançada. Por exemplo, quando a exceção ocorre no código a seguir, o controle é transferido para a cláusula catch.

js
try {
  throw "myException"; // gera uma exceção
} catch (e) {
  // declarações para manipular quaisquer exceções
  logMyErrors(e); // passa o objeto de exceção para o manipulador de erro
}

Cláusulas catch condicionais

Non-standard: This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.

Você pode utilizar uma ou mais cláusulas catch condicionals para manipular exceções específicas. Nesse caso a cláusula catch apropriada será inserida quando a exceção espeficica for lançada. No exemplo a seguir, o código no bloco try pode potencialmente jogar três exceções: TypeError, RangeError (en-US), e EvalError. Quando a exceção ocorre, o controle transfere para a cláusula catch apropriada. Caso a exceção não seja uma das especificadas e uma cláusula catch incondicional for encontrada, o controle é transferido para essa cláusula catch.

Se utilizar uma cláusula catch incondicional com uma ou mais cláusulas catch condicionais, o catch incondicional deve ser especificado por último. Caso contrário, o catch incondicional interceptará todos os tipos de exceção antes que eles alcancem os condicionais.

Nota: Essa funcionalidade não é parte da especificação ECMAScript.

try {
    myroutine(); // pode lançar três tipos de exceções
} catch (e if e instanceof TypeError) {
    // declarações para manipular exceções TypeError
} catch (e if e instanceof RangeError) {
    // declarações para manipular exceções RangeError
} catch (e if e instanceof EvalError) {
    // declarações para manipular exceções EvalError
} catch (e) {
    // declarações para manipular quaisquer exceções não especificadas
    logMyErrors(e); // passa o objeto de exceção para o manipulador de erro
}

E aqui temos como implementar as mesmas "cláusulas catch condicionais" utilizando apenas JavaScript puro conforme a especificação ECMAScript (obviamente é mais verboso, porém, funciona em qualquer lugar):

try {
    myroutine(); // pode lançar três tipos de exceções
} catch (e) {
    if (e instanceof TypeError) {
        // declarações para manipular exceções TypeError
    } else if (e instanceof RangeError) {
        // declarações para manipular exceções RangeError
    } else if (e instanceof EvalError) {
        // declarações para manipular exceções EvalError
    } else {
       // declarações para manipular quaisquer exceções não especificadas
       logMyErrors(e); // passa o objeto de exceção para o manipulador de erro
    }
}

O identificador de exceção

Quando uma exceção é lançada no bloco try, exception_var (ex. o e dentro de catch (e)) armazena o valor especificado pela declaração throw. Você pode usar esse identificador para conseguir informação sobre a exceção que foi lançanda.

Esse identificador é local para a cláusula catch. Ou seja, é criado quando a cláusula catch é introduzida e após terminar sua excecução o identificador não se torna mais disponível.

A cláusula finally

A cláusula finally é executada após a excecução do bloco try e da(s) cláusula(s) catch porém antes das declarações seguintes a declaração try. Ela sempre é executada, independente se uma exceção for lançada ou capturada.

A cláusula finally contém declarações para executarem após a execução do bloco try e da(s) cláusula(s) catch porém antes das declarações seguintes a declaração try. A cláusula finally é excutada independente se uma exceção for lançada ou não. Caso uma exceção seja lançada, as declarações no interior da cláusula finally são executadas mesmo que nenhum catch manipule a exceção.

Você pode utilizar a cláusula finally para fazer seu script falhar graciosamente quando uma exceção ocorrer; por exemplo, você pode precisar liberar um recurso que seu script possui vinculado. O exemplo seguinte abre um aquivo e então executa declarações que utilizam o arquivo (server-side JavaScript permite que você acesse arquivos). Se uma exceção for lançada enquanto o arquivo estiver aberto, a cláusula finally fecha o arquivo antes que o script falhe.

js
openMyFile();
try {
  // vincula o recurso
  writeMyFile(theData);
} finally {
  closeMyFile(); // sempre fecha o recurso
}

Exemplos

Blocos try aninhados

Primeiro vamos ver o que acontece com isso:

try {
  try {
    throw new Error("oops");
  }
  finally {
    console.log("finally");
  }
}
catch (ex) {
  console.error("outer", ex.message);
}

// Resultado
// "finally"
// "outer" "oops"

Agora, caso nós já capturamos a exceção no bloco try interno adicionando um bloco catch

try {
  try {
    throw new Error("oops");
  }
  catch (ex) {
    console.error("inner", ex.message);
  }
  finally {
    console.log("finally");
  }
}
catch (ex) {
  console.error("outer", ex.message);
}

// Resultado:
// "inner" "oops"
// "finally"

E agora, vamos relançar o erro.

try {
  try {
    throw new Error("oops");
  }
  catch (ex) {
    console.error("inner", ex.message);
    throw ex;
  }
  finally {
    console.log("finally");
  }
}
catch (ex) {
  console.error("outer", ex.message);
}

// Resultado:
// "inner" "oops"
// "finally"
// "outer" "oops"

Qualquer exceção lançada será capturada apenas uma vez pelo bloco catch envolvente mais próximo, a não ser que seja relançada. Obviamente qualquer nova exceção elevada no bloco "interno" (pois código em um bloco catch pode fazer algo que lance), será capturado pelo bloco "externo".

Retornando de um bloco finally

Caso o bloco finally retorne um valor, esse valor torna-se o valor de retorno do produto de try-catch-finally inteiro, independente de qualquer declaração return nos blocos try e catch. Isso inclui exceções lançadas dentro do bloco catch:

try {
  try {
    throw new Error("oops");
  }
  catch (ex) {
    console.error("inner", ex.message);
    throw ex;
  }
  finally {
    console.log("finally");
    return;
  }
}
catch (ex) {
  console.error("outer", ex.message);
}

// Resultado:
// "inner" "oops"
// "finally"

O "oops" externo não é lançado devido ao retorno do bloco finally. O mesmo se aplicaria a qualquer valor retornado do bloco catch.

Vejam também