Kiedy używać rzutów w deklaracji metody Java?


82

Więc pomyślałem, że dobrze rozumiem podstawową obsługę wyjątków w Javie, ale ostatnio czytałem kod, który wprowadził mnie w zakłopotanie i wątpliwości. Moją główną wątpliwością, którą chcę się tutaj zająć, jest to, kiedy osoba powinna użyć deklaracji metody Javy, jak poniżej:

    public void method() throws SomeException
    {
         // method body here
    }

Z czytania kilku podobnych postów wynika, że rzucania są używane jako rodzaj deklaracji, że SomeException może zostać wyrzucony podczas wykonywania metody.

Moje zamieszanie pochodzi z kodu, który wyglądał tak:

     public void method() throws IOException
     {
          try
          {
               BufferedReader br = new BufferedReader(new FileReader("file.txt"));
          }
          catch(IOException e)
          {
               System.out.println(e.getMessage());
          }
     }

Czy jest jakiś powód, dla którego chciałbyś użyć rzutów w tym przykładzie? Wygląda na to, że jeśli robisz tylko podstawową obsługę wyjątków dla czegoś takiego jak IOException, po prostu potrzebujesz bloku try / catch i to wszystko.

Odpowiedzi:


79

Jeśli łapiesz typ wyjątku, nie musisz go wyrzucać, chyba że zamierzasz go ponownie wrzucić. W zamieszczonym przez Ciebie przykładzie programista powinien był zrobić jedno lub drugie, a nie jedno i drugie.

Zazwyczaj, jeśli nie zamierzasz robić nic poza wyjątkiem, nie powinieneś tego łapać.

Najbardziej niebezpieczną rzeczą, jaką możesz zrobić, jest złapanie wyjątku i nic z nim nie rób.

Dobra dyskusja na temat tego, kiedy należy zgłaszać wyjątki, znajduje się tutaj

Kiedy zgłosić wyjątek?


2
Czy niezaznaczone wyjątki powinny być również deklarowane w sygnaturze metody za pomocą „rzutów”, czy też praktyką jest używanie „rzutów” tylko dla sprawdzonych wyjątków?
— Cody

Ta odpowiedź nie odnosi się bezpośrednio do głównego aspektu pytania: użycia throwssłowa kluczowego.
— Brent Bradburn

@hvgotcodes Co się stanie, jeśli złapię wyjątek i nic nie zrobię?
— Manoj

@manoj ryzykujesz, że coś się zepsuje i nie będziesz w stanie tego rozgryźć, ponieważ utracone są kluczowe informacje. Są chwile (niekoniecznie java), w których można złapać wyjątek i nic nie robić, ale należy to udokumentować. Na przykład w javascript możesz spróbować wywołać funkcje, które mogą nie istnieć w zależności od przeglądarki. Niekoniecznie jest to błąd wymagający uwagi.
— hvgotcodes

22

Musisz tylko dołączyć klauzulę throws do metody, jeśli metoda zgłasza sprawdzony wyjątek. Jeśli metoda zgłasza wyjątek czasu wykonywania, nie ma takiej potrzeby.

Zobacz tutaj, aby zapoznać się z kontekstem wyjątków zaznaczonych i niezaznaczonych: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

Jeśli metoda wychwytuje wyjątek i zajmuje się nim wewnętrznie (jak w drugim przykładzie), nie ma potrzeby dołączania klauzuli throws.


9

Kod, który oglądałeś, nie jest idealny. Powinieneś albo:

  1. Złap wyjątek i obsłuż go; w takim przypadku throwsjest to niepotrzebne.

  2. Usuń try/catch; w takim przypadku wyjątek będzie obsługiwany przez metodę wywołującą.

  3. Złap wyjątek, prawdopodobnie wykonaj jakąś akcję, a następnie wyślij ponownie wyjątek (nie tylko wiadomość)


2

Masz rację, w tym przykładzie throwsjest to zbędne. Możliwe, że został tam z jakiejś wcześniejszej implementacji - być może wyjątek został pierwotnie wyrzucony, a nie złapany w bloku catch.


2

Wysłany kod jest nieprawidłowy. Powinien zgłosić wyjątek, jeśli przechwytuje określony wyjątek w celu obsługi IOException, ale zgłasza nie przechwycone wyjątki.

Coś jak:

public void method() throws Exception{
   try{
           BufferedReader br = new BufferedReader(new FileReader("file.txt"));
   }catch(IOException e){
           System.out.println(e.getMessage());
   }
}

lub

public void method(){
   try{
           BufferedReader br = new BufferedReader(new FileReader("file.txt"));
   }catch(IOException e){
           System.out.println("Catching IOException");
           System.out.println(e.getMessage());
   }catch(Exception e){
           System.out.println("Catching any other Exceptions like NullPontException, FileNotFoundExceptioon, etc.");
           System.out.println(e.getMessage());
   }

}


1

W podanym przykładzie metoda nigdy nie zgłosi wyjątku IOException, dlatego deklaracja jest nieprawidłowa (ale poprawna). Domyślam się, że oryginalna metoda wyrzuciła IOException, ale została następnie zaktualizowana, aby obsłużyć wyjątek w ramach, ale deklaracja nie została zmieniona.


1

To nie jest odpowiedź, ale komentarz, ale nie mogłem napisać komentarza ze sformatowanym kodem, więc oto komentarz.

Powiedzmy, że jest

public static void main(String[] args) {
  try {
    // do nothing or throw a RuntimeException
    throw new RuntimeException("test");
  } catch (Exception e) {
    System.out.println(e.getMessage());
    throw e;
  }
}

Wynik jest

test
Exception in thread "main" java.lang.RuntimeException: test
    at MyClass.main(MyClass.java:10)

Ta metoda nie deklaruje żadnych wyjątków „rzuca”, ale je odrzuca! Sztuczka polega na tym, że zgłaszane wyjątki to RuntimeExceptions (niezaznaczone), które nie muszą być deklarowane w metodzie. Dla czytelnika metody jest to trochę mylące, ponieważ wszystko, co widzi, to „rzut”; instrukcja, ale bez deklaracji wyjątku zgłasza

Teraz, jeśli mamy

public static void main(String[] args) throws Exception {
  try {
    throw new Exception("test");
  } catch (Exception e) {
    System.out.println(e.getMessage());
    throw e;
  }
}

MUSIMY zadeklarować wyjątki „rzuca” w metodzie, w przeciwnym razie otrzymamy błąd kompilatora.


Kompilator przeprowadza zaskakująco wyrafinowaną analizę statyczną, aby zdecydować, czy throwsjest to wymagane.
— Brent Bradburn
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.