W3docs

Bloco finally em Java

Execute código de limpeza com blocos finally que sempre rodam, independente de uma exceção ter sido lançada ou não.

Um bloco finally é executado independentemente de como o try termina — conclusão normal, exceção capturada, exceção não capturada, ou até mesmo um return antecipado. Essa garantia é seu único propósito: é onde você coloca a limpeza que precisa acontecer, independentemente de tudo. Fechar um handle de arquivo, liberar um lock, restaurar o estado de uma thread — qualquer coisa cuja ausência deixaria o programa em uma condição pior do que quando começou.

A estrutura

try {
  // risky code
} catch (SomeException e) {
  // optional — zero or more catches
} finally {
  // always runs after the try (and any matching catch)
}

Você pode combinar finally com catch, sem nenhum catch (try { ... } finally { ... }), ou com múltiplos catches. As partes se compõem livremente.

O que "sempre executa" significa

Um bloco finally é executado quando o controle sai do try, independentemente de como:

  • Fim normal do bloco tryfinally executa após a última instrução.
  • Uma exceção lançada do tryfinally executa após o catch correspondente terminar (ou, se nenhum catch corresponder, logo antes de a exceção se propagar).
  • return dentro de try ou catchfinally executa antes de o retorno realmente ter efeito.
  • break ou continue que sairia do tryfinally executa antes do salto.

As únicas formas de ignorar o finally são: a própria JVM morre (System.exit, falta de energia, Runtime.halt), um loop infinito ou deadlock dentro do try, ou Thread.stop (que é depreciado exatamente por essa razão). Para tudo que você escreve em código de aplicação normal, finally é uma garantia rígida.

try {
  return computeAnswer();    // even though there's a return here,
} finally {
  cleanup();                 // this runs before the method actually returns
}

Para que serve o finally

A resposta honesta é: limpeza de recursos, quase sempre. Antes do Java 7 introduzir o try-with-resources, a forma canônica era:

InputStream in = null;
try {
  in = new FileInputStream(path);
  // read from in...
} catch (IOException e) {
  // handle
} finally {
  if (in != null) {
    try { in.close(); } catch (IOException ignored) { /* */ }
  }
}

Esse try/catch aninhado em torno de close() no finally é exatamente o tipo de ruído que o try-with-resources foi criado para eliminar. Veremos isso no próximo capítulo. Mas entender para que o finally serve torna o novo construto mais compreensível.

Além de recursos, finally é útil para:

  • Restaurar estado compartilhado que você mutou durante o try — incrementar um contador de profundidade, alternar um flag, trocar um ThreadLocal.
  • Liberar locks adquiridos manualmente (Lock.lock()try { ... } finally { lock.unlock(); }).
  • Parar temporizadores ou fechar transações que não implementam AutoCloseable.

Para que o finally não serve

Não escreva lógica que produz resultados em finally. O bloco executa independentemente do resultado — ele não sabe se o try teve sucesso. Se você colocar commit() em finally, você fará commit mesmo em caso de falha.

E não use return em finally. Este é um dos cantos genuinamente perigosos da linguagem:

try {
  return 1;
} finally {
  return 2;     // wins — the method returns 2 and the original return is lost
}

O return (ou throw) dentro de finally sobrepõe qualquer retorno ou exceção do try. A exceção que estava prestes a se propagar é silenciosamente descartada. A maioria dos linters sinaliza isso como erro por esse motivo. A regra: finally faz limpeza; finally não produz valores.

Ordem de execução

Quando um catch e um finally estão presentes:

try   { ... }
catch { ... }
finally { ... }

A ordem é exatamente a que você esperaria: try executa, se lançar uma exceção e um catch corresponder, esse catch executa, e finally executa após whichever of those did. Se finally então lançar uma exceção, esse novo lançamento substitui o que estava se propagando do try ou catch — mais uma razão para manter o finally quieto.

Um exemplo prático

Instrumentamos uma pequena "transação" com try/catch/finally e a chamamos de três maneiras diferentes: sucesso normal, falha recuperável e uma irrecuperável. O finally executa nos três casos, que é o ponto central.

java— editable, runs on the server

Na terceira chamada, doWork lança uma RuntimeException que o catch local não corresponde. O finally ainda executa e imprime "release lock" antes de a exceção continuar se propagando até main. Essa é a propriedade que você quer do código de limpeza — ela não depende de o tratamento ter tido sucesso.

O que vem a seguir

O padrão "abrir um recurso, trabalhar com ele, fechá-lo em finally" é tão comum que Java criou uma instrução dedicada para isso. Continue para Java try-with-resources.

Prática

Prática
O que este método retorna?\n\n```java\nstatic int demo() {\n try {\n return 1;\n } finally {\n return 2;\n }\n}\n```
O que este método retorna?\n\n```java\nstatic int demo() {\n try {\n return 1;\n } finally {\n return 2;\n }\n}\n```
Was this page helpful?