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.

jbranchaud
źródło

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?

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

Shane Bell
źródło
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ść)

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

RevBingo
źródło
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());
   }

}

Ignacio lucatero
źródło
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.

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

Αλέκος
źródło
Kompilator przeprowadza zaskakująco wyrafinowaną analizę statyczną, aby zdecydować, czy throwsjest to wymagane.
Brent Bradburn