Diferença entre try-finally e try-catch

90

Qual é a diferença entre

try {
    fooBar();
} finally {
    barFoo();
}

e

try {
  fooBar();
} catch(Throwable throwable) {
    barFoo(throwable); // Does something with throwable, logs it, or handles it.
}

Eu gosto mais da segunda versão porque ela me dá acesso ao Throwable. Existe alguma diferença lógica ou uma convenção preferencial entre as duas variações?

Além disso, há uma maneira de acessar a exceção da cláusula finally?

Vijay Kotari
fonte

Respostas:

121

Estas são duas coisas diferentes:

  • O bloco catch só é executado se uma exceção for lançada no bloco try.
  • O bloco finally é executado sempre após o bloco try (-catch), se uma exceção for lançada ou não.

Em seu exemplo, você não mostrou a terceira construção possível:

try {
    // try to execute this statements...
}
catch( SpecificException e ) {
    // if a specific exception was thrown, handle it here
}
// ... more catches for specific exceptions can come here
catch( Exception e ) {
    // if a more general exception was thrown, handle it here
}
finally {
    // here you can clean things up afterwards
}

E, como @codeca diz em seu comentário, não há como acessar a exceção dentro do bloco finally, pois o bloco finally é executado mesmo que não haja exceção.

Claro que você pode declarar uma variável que contém a exceção fora do seu bloco e atribuir um valor dentro do bloco catch. Depois disso, você pode acessar essa variável dentro do seu bloco finally.

Throwable throwable = null;
try {
    // do some stuff
}
catch( Throwable e ) {
    throwable = e;
}
finally {
    if( throwable != null ) {
        // handle it
    }
}
tangens
fonte
11
Um corolário disso é que você não pode acessar o Throwabledo finallybloco, porque pode não haver um Throwable.
Dean Harding
11

Não são variações, são coisas fundamentalmente diferentes. finallyé executado sempre , catchapenas quando ocorre uma exceção.

Michiel Buddingh
fonte
7

Finalmente, os blocos de captura são bastante diferentes:

  • Dentro do bloco catch, você pode responder à exceção lançada. Este bloco é executado apenas se houver uma exceção não tratada e o tipo corresponder a um ou for subclasse daquele especificado no parâmetro do bloco catch.
  • Finalmente, será sempre executado após blocos try e catch, haja uma exceção levantada ou não.

assim

try {
  //some code
}
catch (ExceptionA) {
  // Only gets executed if ExceptionA 
  // was thrown in try block
}
catch (ExceptionB) {
  // Only executed if ExceptionB was thrown in try 
  // and not handled by first catch block
}

é diferente de

try {
  //some code
}
finally {
  // Gets executed whether or not 
  // an exception was thrown in try block
}

significativamente.

Se você definir um bloco de teste, você deve definir

  1. finalmente um bloco, ou
  2. um ou mais blocos de captura, ou
  3. um ou mais blocos de captura e um bloco finalmente

Portanto, o código a seguir também seria válido:

try {
  //some code
}
catch (ExceptionA) {
  // Only gets executed if 
  // ExceptionA was thrown in try block
}
catch (ExceptionB) {
  // Only executed if ExceptionB was thrown in 
  // try and not handled by first catch block
}
//even more catch blocks
finally {
  // Gets executed whether or not an 
  // exception was thrown in try block
}
TheMorph
fonte
4

try é usado para executar um método que pode lançar uma exceção

catch é usado para "capturar" parar essa exceção

finally é usado para qualquer limpeza necessária dessa exceção sendo capturada ou não

try{
    myObject.riskyMethod(); // run a method that may throw an exception
}
catch(Exception ex){
    myLogger.log(ex.Message); // "catch" stop that exception
}
finally{
    myObject = null; // clean up needed from that exception being caught
}
Kieran
fonte
3
try {
    statements;
} catch (exceptionType1 e1) {      // one or multiple
    statements;                 
} catch (exceptionType2 e2) {
    statements;
}    
...
} finally {                                 // one or none
    statements;
}
  1. Todas as instruções try devem incluir uma cláusula catch ou uma cláusula finally
  2. Pode ter várias cláusulas catch, mas apenas uma cláusula finally
  3. Durante qualquer execução, se ocorrer algum erro, o Controle é transferido para o bloco Catch apropriado e executa as instruções e o bloco Finalmente é executado.

Não importa o que o bloco finally seja sempre executado, então, em geral, o bloco finally é usado, quando você tem sessões, conexões de banco de dados ou arquivos ou sockets estão abertos, então o código para fechar essas conexões será colocado. Isso é apenas para garantir que em um aplicativo não haja vazamentos de memória ou qualquer outro problema não deve ocorrer.

gmhk
fonte
3

Finalmente, os blocos de captura são bastante diferentes:

Dentro do bloco catch, você pode responder à exceção lançada. Este bloco é executado apenas se houver uma exceção não tratada e o tipo corresponder a um ou for uma subclasse daquele especificado no parâmetro do bloco catch. Finalmente, será sempre executado após os blocos try e catch, haja uma exceção levantada ou não.

Tutorial Android
fonte
2

Em Minha pesquisa Finalmente o bloco é sempre executado e é principalmente "usado para que todas as conexões abertas sejam fechadas" e para destruir algo que está rodando desnecessariamente.

Hari Krishna
fonte
2

Geralmente, quando usamos quaisquer recursos como streams, conexões etc., temos que fechá-los explicitamente usando finally block. No programa abaixo, estamos lendo dados de um arquivo usando FileReader e fechando-o usando finally block.

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class ReadData_Demo {

   public static void main(String args[]){
      FileReader fr=null;       
      try{
         File file=new File("file.txt");
         fr = new FileReader(file);  char [] a = new char[50];
         fr.read(a); // reads the content to the array
         for(char c : a)
         System.out.print(c); //prints the characters one by one
      }catch(IOException e){
          e.printStackTrace();
       }
       finally{ 
          try{
              fr.close();
          }catch(IOException ex){       
               ex.printStackTrace();
           }
       }
    }

}

Talvez outros caras como eu tenham procurado algo assim.

Informações desta página tutpoint


fonte
1

Finalmente o bloco é sempre executado. O bloco Catch é executado apenas quando uma exceção que corresponde ao parâmetro dos blocos é capturada.

mkorpela
fonte
1

Mesmo na primeira forma, você pode registrá-lo no método de chamada. Portanto, não há grande vantagem, a menos que você queira fazer algum tratamento especial ali mesmo.

fastcodejava
fonte
0

O bloco Try conterá as instruções que irão gerar a exceção. O bloco catch manterá a referência lançada do bloco try e as mensagens necessárias são geradas a partir do bloco catch. Finalmente, o bloco também é usado para fechar os recursos usados ​​como fechamento de io, fechamento de arquivo, fechamento de dB. No Java -9, o recurso try-with aprimorado surgiu onde os recursos são declarados fora do try..in enchanced try with resource o bloco catch é mandatório

srinija
fonte