Versuch / Fang versus Würfe Ausnahme


117

Sind diese Code-Anweisungen gleichwertig? Gibt es einen Unterschied zwischen ihnen?

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

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

3
Keine wirkliche Antwort, aber Sie könnten an Ned Batchelders Artikel Exceptions in the Rainforest interessiert sein , der die allgemeinen Fälle erklärt, in denen der eine oder andere Stil vorzuziehen ist.
Daniel Pryden

1
Anstatt "showException (e)" im catch zu haben, haben Sie gefragt, ob Sie stattdessen "throw e" im catch haben (oder überhaupt nicht try / catch)?
MacGyver

Antworten:


146

Ja, es gibt einen großen Unterschied - letzterer verschluckt die Ausnahme (zeigt sie zugegebenermaßen), während der erste sie ausbreiten lässt. (Ich gehe davon aus, dass showExceptiondas nicht neu geworfen wird.)

Wenn Sie also die erste Methode aufrufen und "etwas tun" fehlschlägt, muss der Aufrufer die Ausnahme behandeln. Wenn Sie die zweite Methode aufrufen und "etwas tun" fehlschlägt, wird dem Aufrufer überhaupt keine Ausnahme angezeigt. Dies ist im Allgemeinen eine schlechte Sache, es sei denn, er showExceptionhat die Ausnahme wirklich behandelt, Fehler behoben und im Allgemeinen sichergestellt das calculateAreahat seinen Zweck erreicht.

Sie werden in der Lage sein , dies zu sagen, weil Sie nicht die erste Methode ohne aufrufen können entweder fangen Exceptionselbst oder erklären , dass Ihre Methode es werfen könnte.


12
Wenn Sie erwähnen, dass "es sei denn, es hat die Ausnahme wirklich behandelt", ist das ein großartiger Punkt. Ich dachte nur, ich würde hinzufügen, dass das Abfangen von "Ausnahme" selbst selten zu einer intelligenten "Behandlung" der tatsächlichen Ausnahme führt, weshalb die Leute empfehlen, dass Sie die spezifischste mögliche Ausnahme abfangen.
Bill K

17
+1. Weil Jon Skeet mehr Ruf braucht. Oh, und die Antwort war auch gut.
Jonathan Spiller

20

Zuerst throws Exceptionmuss der Anrufer das erledigen Exception. Der zweite fängt und verarbeitet Exceptionintern, sodass der Anrufer keine Ausnahmebehandlung durchführen muss.


Kurz gesagt, ich sollte immer die zweite verwenden. Habe ich recht? Die erste ist eigentlich eine Methode, die an verschiedenen Stellen des Programms verwendet wird. Deshalb habe ich beschlossen, die Anweisungen für die weitere Verwendung zusammenzufassen, aber nachdem ich das getan habe, merke ich jetzt, dass T einen großen Fehler gemacht hat.
Carlos

9
Nein, beide Muster werden benötigt. Wenn Ihre Methode die Ausnahme behandeln kann, verwenden Sie das zweite Muster. Wenn nicht, verwenden Sie das erste, um den Anrufer zu benachrichtigen.
Andreas Dolk

Welche Version Sie verwenden, hängt von Ihren Anforderungen ab - im Grunde genommen auf welcher Ebene müssen Sie diese Ausnahme behandeln. Der Anrufer muss entsprechend codiert werden. Wenn ein Aufrufer die erste Version aufgerufen hat und Sie die Methodendefinition durch die zweite Version ersetzen, wird Ihr Aufrufercode gezwungen, die Ausnahme zu behandeln, da dies eine überprüfte Ausnahme ist.
Samitgaur

16

Ja. Für die deklarierte Version ist throws Exceptionder aufrufende Code erforderlich, um die Ausnahme zu behandeln, für die explizit behandelte Version jedoch nicht.

dh einfach:

performCalculation();

Verschieben der Last der Behandlung der Ausnahme auf den Anrufer:

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

6

Ja, es gibt einen großen Unterschied zwischen ihnen. Im ersten Codeblock übergeben Sie die Ausnahme an den aufrufenden Code. Im zweiten Codeblock erledigen Sie das selbst. Welche Methode richtig ist, hängt ganz davon ab, was Sie tun. In einigen Fällen soll Ihr Code die Ausnahme behandeln (wenn eine Datei nicht gefunden wird und Sie sie beispielsweise erstellen möchten), in anderen Fällen soll der aufrufende Code die Ausnahme behandeln (eine Datei wird nicht gefunden) und sie müssen ein neues angeben oder es erstellen).

Auch im Allgemeinen möchten Sie keine generische Ausnahme abfangen. Stattdessen möchten Sie nur bestimmte fangen, z. B. FileNotFoundExceptionoder IOExceptionweil sie unterschiedliche Bedeutungen haben können.


3

Es gibt ein bestimmtes Szenario, in dem wir keine Würfe verwenden können. Wir müssen Try-Catch verwenden. Es gibt eine Regel "Eine überschriebene Methode kann keine zusätzliche Ausnahme auslösen als die, die ihre übergeordnete Klasse auslöst". Wenn es eine zusätzliche Ausnahme gibt, die mit try-catch behandelt werden sollte. Betrachten Sie dieses Code-Snippet. Es gibt eine einfache Basisklasse

package trycatchvsthrows;

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

und es ist abgeleitete Klasse:

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
    }
}

Wenn wir thread.sleep () aufrufen müssen, müssen wir try-catch verwenden, hier können wir nicht verwenden:

 public void show() throws InterruptedException

weil überschriebene Methode keine zusätzlichen Ausnahmen auslösen kann.


Ich glaube, dass nicht jeder über diese Einschränkung informiert ist. Gut spitz.
ivanleoncz

1

Ich gehe davon aus, dass Sie sich mit "identisch" auf Verhalten beziehen.

Ein Verhalten einer Funktion kann bestimmt werden durch:

1) Rückgabewert

2) Ausgelöste Ausnahmen

3) Nebenwirkungen (dh Änderungen im Heap, im Dateisystem usw.)

In diesem Fall gibt die erste Methode jede Ausnahme weiter, während die zweite keine aktivierte Ausnahme auslöst und die meisten nicht aktivierten Ausnahmen ebenfalls verschluckt, sodass das Verhalten anders ist.

Wenn Sie jedoch garantieren, dass "etwas tun" niemals eine Ausnahme auslöst, ist das Verhalten identisch (obwohl der Compiler in der ersten Version vom Aufrufer verlangt, die Ausnahme zu behandeln).

--bearbeiten--

Aus Sicht des API-Designs unterscheiden sich die Methoden in ihrem Vertrag völlig. Es wird auch nicht empfohlen, eine Klassenausnahme zu werfen. Versuchen Sie, etwas Spezifischeres zu werfen, damit der Anrufer die Ausnahme besser behandeln kann.


1

Wenn Sie eine Ausnahme ausgelöst haben, sollte die untergeordnete Methode (die diese überschreibt) die Ausnahme behandeln

Beispiel:

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

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

0

Oft möchten Sie, dass der Anrufer die Ausnahme behandelt. Angenommen, der Aufrufer ruft eine Methode auf, die eine andere Methode aufruft, die eine andere Methode aufruft. Anstatt dass jede Methode die Ausnahme behandelt, können Sie sie einfach beim Aufrufer behandeln. Es sei denn, Sie möchten etwas in einer der Methoden tun, wenn diese Methode fehlschlägt.


0

Der Aufrufer dieser Methode muss diese Ausnahme entweder abfangen oder deklarieren, dass sie in ihrer Methodensignatur erneut ausgelöst wird.

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

Im folgenden Try-Catch-Block-Beispiel. Der Aufrufer dieser Methode muss sich nicht um die Behandlung der Ausnahme kümmern, da diese bereits behoben wurde.

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

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

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

Dies löst die Ausnahme aus, sodass der Anrufer für die Behandlung dieser Ausnahme verantwortlich ist. Wenn der Anrufer die Ausnahme jedoch nicht behandelt, wird sie möglicherweise an jvm übergeben, was zu einer abnormalen Beendigung des Programms führen kann.

Während im zweiten Fall:

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

Hier wird die Ausnahme vom Angerufenen behandelt, sodass keine Möglichkeit einer abnormalen Beendigung des Programms besteht.

Try-Catch ist der empfohlene Ansatz.

IMO,

  • Löst ein Schlüsselwort aus, das hauptsächlich mit geprüften Ausnahmen verwendet wird, um den Compiler zu überzeugen, garantiert jedoch nicht die normale Beendigung des Programms.

  • Das Schlüsselwort delegiert die Verantwortung für die Ausnahmebehandlung an
    den Aufrufer (JVM oder eine andere Methode).

  • Das Schlüsselwort "Throws" ist nur für aktivierte Ausnahmen erforderlich. Für nicht aktivierte Ausnahmen wird das Schlüsselwort "throw" nicht verwendet.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.