Różnica między próbowaniem w końcu i łapaniem

91

Jaka jest różnica pomiędzy

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

i

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

Druga wersja podoba mi się bardziej, ponieważ daje mi dostęp do Throwable. Czy jest jakaś logiczna różnica lub preferowana konwencja między tymi dwiema odmianami?

Czy istnieje również sposób uzyskania dostępu do wyjątku z klauzuli last?

Vijay Kotari
źródło

Odpowiedzi:

121

To są dwie różne rzeczy:

  • Blok catch jest wykonywany tylko wtedy, gdy wyjątek zostanie zgłoszony w bloku try.
  • Ostateczny blok jest wykonywany zawsze po bloku try (-catch), jeśli zostanie zgłoszony wyjątek lub nie.

W swoim przykładzie nie pokazałeś trzeciej możliwej konstrukcji:

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
}

I, jak mówi @codeca w swoim komentarzu, nie ma możliwości uzyskania dostępu do wyjątku wewnątrz ostatniego bloku, ponieważ ostatni blok jest wykonywany, nawet jeśli nie ma wyjątku.

Oczywiście możesz zadeklarować zmienną, która przechowuje wyjątek na zewnątrz twojego bloku i przypisać wartość wewnątrz bloku catch. Następnie możesz uzyskać dostęp do tej zmiennej w swoim ostatnim bloku.

Throwable throwable = null;
try {
    // do some stuff
}
catch( Throwable e ) {
    throwable = e;
}
finally {
    if( throwable != null ) {
        // handle it
    }
}
tangens
źródło
11
Następstwem do tego jest to, że nie może uzyskać dostęp do Throwableod finallybloku, ponieważ nie może byćThrowable .
Dean Harding
11

To nie są odmiany, to zasadniczo różne rzeczy. finallyjest wykonywany zawsze , catchtylko gdy wystąpi wyjątek.

Michiel Buddingh
źródło
7

Wreszcie bloki catch są zupełnie inne:

  • W bloku catch możesz odpowiedzieć na zgłoszony wyjątek. Ten blok jest wykonywany tylko wtedy, gdy istnieje nieobsługiwany wyjątek, a typ jest zgodny z jedną lub jest podklasą tego określonego w parametrze bloku catch.
  • Ostatecznie będzie zawsze wykonywane po blokach try i catch, niezależnie od tego, czy wystąpił wyjątek, czy nie.

Więc

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
}

różni się od

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

znacząco.

Jeśli zdefiniujesz blok try, musisz zdefiniować

  1. jeden w końcu blok, lub
  2. jeden lub więcej bloków catch lub
  3. jeden lub więcej bloków catch i jeden blok końcowy

Więc poniższy kod również byłby prawidłowy:

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
źródło
4

try służy do uruchamiania metody, która może zgłosić wyjątek

catch służy do „przechwytywania” zatrzymania tego wyjątku

finally jest używany do czyszczenia potrzebnego po wykryciu tego wyjątku lub nie

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
źródło
3
try {
    statements;
} catch (exceptionType1 e1) {      // one or multiple
    statements;                 
} catch (exceptionType2 e2) {
    statements;
}    
...
} finally {                                 // one or none
    statements;
}
  1. Wszystkie instrukcje try muszą zawierać jedną klauzulę catch lub klauzulę last
  2. Może mieć wiele klauzul catch, ale tylko jedną klauzulę last
  3. Jeśli podczas dowolnego wykonania wystąpią jakiekolwiek błędy, Sterowanie jest przenoszone do odpowiedniego bloku Catch i wykonuje instrukcje, a następnie wykonywany jest blok Final.

Bez względu na to, co blok Final jest zawsze wykonywany, więc generalnie blok Final jest używany, gdy masz sesje, połączenia z bazą danych lub pliki lub gniazda są otwarte, kod zamykający te połączenia zostanie umieszczony. Ma to na celu upewnienie się, że w aplikacji nie wystąpią wycieki pamięci ani żadne inne problemy.

gmhk
źródło
3

Wreszcie bloki catch są zupełnie inne:

W bloku catch możesz odpowiedzieć na zgłoszony wyjątek. Ten blok jest wykonywany tylko wtedy, gdy istnieje nieobsługiwany wyjątek, a typ jest zgodny z jedną lub jest podklasą tego określonego w parametrze bloku catch. Ostatecznie będzie zawsze wykonywany po blokach try and catch, niezależnie od tego, czy wystąpił wyjątek, czy nie.

Samouczek na Androida
źródło
2

W Moich badaniach blok Ostatecznie jest zawsze wykonywany i jest głównie „używany do zamykania wszelkich otwartych połączeń” oraz do niszczenia czegoś, co działa niepotrzebnie.

Hari krishna
źródło
2

Generalnie, gdy używamy jakichkolwiek zasobów, takich jak strumienie, połączenia itp., Musimy je jawnie zamknąć, używając funkcji last block. W podanym niżej programie odczytujemy dane z pliku za pomocą FileReadera i zamykamy go za pomocą bloku final.

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();
           }
       }
    }

}

Może inni faceci tacy jak ja szukali czegoś takiego.

Informacje z tej strony tutpoint


źródło
1

Ostatecznie blok jest zawsze wykonywany. Blok przechwytywania jest wykonywany tylko wtedy, gdy zostanie przechwycony wyjątek zgodny z parametrem bloków.

mkorpela
źródło
1

Nawet w pierwszej formie można było to zalogować w metodzie wywołującej. Nie ma więc dużej przewagi, chyba że chcesz wykonać specjalne czynności właśnie tam.

fastcodejava
źródło
0

Try block będzie zawierał instrukcje, które mają wywołać wyjątek. Blok catch będzie przechowywać odwołanie wyrzucone z bloku try, a wymagane komunikaty są generowane z bloku catch. Ostatecznie blok jest również używany do zamykania używanych zasobów, takich jak zamykanie io, zamykanie pliku, zamykanie dB .. W Javie -9 pojawiło się rozszerzenie zasobu try-with, w którym zasoby są zadeklarowane poza try..in ulepszone try z zasobem blok catch jest obowiązkowe

srinija
źródło