try / catch versus rzuca Wyjątek


117

Czy te instrukcje kodu są równoważne? Czy jest między nimi jakaś różnica?

private void calculateArea() throws Exception {
    ....do something
}

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

3
Nie do końca jest to odpowiedź, ale możesz być zainteresowany artykułem Neda Batcheldera Exceptions in the Rainforest , który pomaga wyjaśnić ogólne przypadki, w których preferowany jest jeden lub drugi styl.
Daniel Pryden,

1
zamiast mieć „showException (e)” w haczyku, czy pytałeś, czy zamiast tego miałeś „rzuca e” w haczyku (czy w ogóle nie masz próby / złapania)?
MacGyver

Odpowiedzi:


146

Tak, jest ogromna różnica - ta druga połyka wyjątek (co prawda, pokazując), a pierwsza pozwoli mu się rozmnażać. (Zakładam, że showExceptionto nie powoduje powtórzenia.)

Więc jeśli wywołasz pierwszą metodę i "zrób coś" nie powiedzie się, to wywołujący będzie musiał obsłużyć wyjątek. Jeśli wywołasz drugą metodę i "zrób coś" zawiedzie, wywołujący w ogóle nie zobaczy wyjątku ... co jest ogólnie złą rzeczą, chyba showExceptionże naprawdę obsłużył wyjątek, naprawił wszystko, co było nie tak i ogólnie upewnił się który calculateAreaosiągnął swój cel.

Będziesz w stanie powiedzieć to, ponieważ nie można nazwać pierwszą metodę bez albo łapanie Exceptionsię lub deklarując, że metoda może go wyrzucić zbyt.


12
Kiedy wspomina się, że „Chyba że rzeczywiście załatwił wyjątek”, to świetna uwaga. Pomyślałem tylko, że dodam, że samo wychwycenie „Wyjątku” rzadko prowadzi do inteligentnego „obsłużenia” rzeczywistego wyjątku, co jest powodem, dla którego ludzie zalecają złapanie najbardziej konkretnego możliwego wyjątku.
Bill K

17
+1. Ponieważ Jon Skeet potrzebuje większej reputacji. Aha, i odpowiedź też była dobra.
Jonathan Spiller

20

Pierwszy throws Exception, więc dzwoniący musi obsłużyć Exception. Drugi przechwytuje i obsługuje Exceptionwewnętrznie, więc wywołujący nie musi wykonywać żadnej obsługi wyjątków.


Krótko mówiąc, zawsze powinienem używać drugiego. Czy mam rację? Pierwsza z nich to właściwie metoda używana w różnych punktach programu. Dlatego zdecydowałem się zebrać razem instrukcje do dalszego użycia, ale kiedy to zrobiłem, teraz zdaję sobie sprawę, że T popełnił duży błąd ..
carlos

9
Nie, oba wzory są potrzebne. Jeśli Twoja metoda może obsłużyć wyjątek, użyj drugiego wzorca, jeśli nie, użyj pierwszego, aby powiadomić wywołującego.
Andreas Dolk

To, której wersji używasz, zależy od twoich wymagań - w zasadzie na jakim poziomie musisz obsłużyć ten wyjątek. Dzwoniący musi być odpowiednio zakodowany. Jeśli obiekt wywołujący wywoływał pierwszą wersję i zastąpisz definicję metody drugą wersją, kod obiektu wywołującego zostanie zmuszony do obsługi wyjątku, ponieważ jest to wyjątek sprawdzony.
samitgaur

16

Tak. Wersja, która deklaruje, throws Exceptionbędzie wymagała kodu wywołującego do obsługi wyjątku, podczas gdy wersja, która obsługuje go jawnie, nie będzie.

czyli po prostu:

performCalculation();

vs. przeniesienie ciężaru obsługi wyjątku na dzwoniącego:

try {
    performCalculation();
catch (Exception e) {
    // handle exception
}

6

Tak, jest między nimi ogromna różnica. W pierwszym bloku kodu przekazujesz wyjątek do kodu wywołującego. W drugim bloku kodu radzisz sobie sam. To, która metoda jest poprawna, zależy całkowicie od tego, co robisz. W niektórych przypadkach chcesz, aby kod obsługiwał wyjątek (jeśli plik nie został znaleziony i chcesz go utworzyć, na przykład), ale w innych chcesz, aby kod wywołujący obsługiwał wyjątek (plik nie został znaleziony i muszą określić nowy lub go utworzyć).

Ogólnie rzecz biorąc, nie chcesz też łapać ogólnego wyjątku. Zamiast tego będziesz chciał wyłapać tylko konkretne, takie jak FileNotFoundExceptionlub IOExceptionponieważ mogą oznaczać różne rzeczy.


3

Jest jeden konkretny scenariusz, w którym nie możemy używać rzutów, musimy użyć try-catch. Istnieje zasada „Przesłonięta metoda nie może zgłosić żadnego dodatkowego wyjątku poza tym, co zgłasza jej klasa nadrzędna”. Jeśli jest jakiś dodatkowy wyjątek, który powinien zostać obsłużony za pomocą try-catch. Rozważ ten fragment kodu. Istnieje prosta klasa bazowa

package trycatchvsthrows;

public class Base {
    public void show()
    {
        System.out.println("hello from base");
    }
}

i jego klasa pochodna:

package trycatchvsthrows;

public class Derived extends Base {

    @Override
    public void show()   {
        // TODO Auto-generated method stub
        super.show();

        Thread thread= new Thread();
        thread.start();
        try {
            thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // thread.sleep(10);
        // here we can not use public void show() throws InterruptedException 
        // not allowed
    }
}

Kiedy musimy wywołać funkcję thread.sleep () jesteśmy zmuszeni użyć try-catch, tutaj nie możemy użyć:

 public void show() throws InterruptedException

ponieważ zastąpiona metoda nie może generować dodatkowych wyjątków.


Uważam, że nie wszyscy są świadomi tego zastrzeżenia. Dobrze spiczaste.
ivanleoncz

1

Zakładam, że przez „identyczne” masz na myśli zachowanie.

Zachowanie funkcji można określić przez:

1) Wartość zwracana

2) Zgłoszone wyjątki

3) Efekty uboczne (tj. Zmiany w stercie, systemie plików itp.)

W tym przypadku pierwsza metoda propaguje każdy wyjątek, podczas gdy druga nie zgłasza żadnego sprawdzonego wyjątku i połyka również większość niezaznaczonych wyjątków, więc zachowanie JEST inne.

Jeśli jednak zagwarantujesz, że „zrób coś” nigdy nie zgłosi wyjątku, wówczas zachowanie będzie identyczne (chociaż kompilator będzie wymagał od obiektu wywołującego obsługi wyjątku w pierwszej wersji)

--edytować--

Z punktu widzenia projektowania API metody są zupełnie inne w ich umowie. Ponadto nie jest zalecane rzucanie wyjątku klasy. Spróbuj wrzucić coś bardziej konkretnego, aby umożliwić wywołującemu lepszą obsługę wyjątku.


1

Jeśli wyrzuciłeś wyjątek, metoda potomna (która przesłania to) powinna obsłużyć wyjątek

przykład:

class A{
public void myMethod() throws Exception{
 //do something
}
}

A a=new A();
try{
a.myMethod();
}catch Exception(e){
//handle the exception
}

0

Wiele razy chcesz, aby wywołujący obsłużył wyjątek. Powiedzmy, że wywołujący wywołuje metodę, która wywołuje inną metodę, która wywołuje inną metodę, zamiast obsługiwać wyjątek przez każdą metodę, możesz po prostu obsłużyć to wywołującemu. Chyba że chcesz coś zrobić w jednej z metod, gdy ta metoda zawodzi.


0

Obiekt wywołujący tej metody będzie musiał albo przechwycić ten wyjątek, albo zadeklarować go do ponownego wygenerowania w sygnaturze metody.

private void calculateArea() throws Exception {
    // Do something
}

W poniższym przykładzie bloku try-catch. Obiekt wywołujący tę metodę nie musi martwić się obsługą wyjątku, ponieważ został on już załatwiony.

private void calculateArea() {
    try {
        // Do something

    } catch (Exception e) {
        showException(e);
    }
}

0
private void calculateArea() throws Exception {
    ....do something
}

Powoduje to zgłoszenie wyjątku, więc wywołujący jest odpowiedzialny za obsługę tego wyjątku, ale jeśli wywołujący nie obsługuje wyjątku, może to być przekazane do jvm, co może spowodować nieprawidłowe zakończenie programu.

Natomiast w drugim przypadku:

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

Tutaj wyjątek jest obsługiwany przez wywoływanego, więc nie ma szans na nieprawidłowe zakończenie programu.

Spróbuj złapać to zalecane podejście.

IMO,

  • Zgłasza słowo kluczowe najczęściej używane z wyjątkami Checked w celu przekonania kompilatora, ale nie gwarantuje normalnego zakończenia programu.

  • Słowo kluczowe throws deleguje odpowiedzialność za obsługę wyjątków
    na obiekt wywołujący (JVM lub inną metodę).

  • Słowo kluczowe throws jest wymagane tylko w przypadku zaznaczonych wyjątków, w przypadku wyjątków niezaznaczonych nie jest używane słowo kluczowe throws.

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.