Frage

Ich denke, Ausnahme.FillinStacktrace sollte Ausnahme oder abgeleitete Ausnahmebobjekte zurückgeben. In Anbetracht der beiden folgenden Funktionen,

public static void f() throws Throwable {
    try {
        throw new Throwable();
    } catch (Exception e) {
        System.out.println("catch exception e");
        e.printStackTrace();
    } 
}
public static void g() throws Throwable {
    try {
        try {
            throw new Exception("exception");
        } catch (Exception e) {
            System.out.println("inner exception handler");
            throw e.fillInStackTrace();
        }
    } catch (Exception e) {
        System.out.println("outer exception handler");
        e.printStackTrace();
    }
}
  1. Das exception handler konnte das nicht fangen new Throwable() in der ersten Funktion f().
  2. Das exception handler könnte das fangen e.fillInstackTrace() in der zweiten Funktion g().
  3. Aber die zweite Funktion g() müsste noch throws Throwable. Das ist wirklich seltsam, da wir fangen konnten e.fillInstackTrace().

Meine Frage ist also, warum keine Ausnahme.

BEARBEITEN:
Zu klären Meine Frage: Was ich mit "seltsamer Syntax" meine, sind

  1. Seit Exception.fillInStackTrace() Rückkehr Throwable Referenz, der Ausnahmebehandler, der erhalten Exception Referenz sollte nicht in der Lage sein, die Ausnahme zu fangen return (Exception)e.fillInstackTrace().
  2. Da es so konzipiert ist, dass der Ausnahmebehandler wiedererlangt Exception Referenz könnte mit dem verwandt sein Throwable Ausnahme, es besteht keine Notwendigkeit, die Methode zu markieren g() Würfe Throwable AUCECT.But Java Compiler würde uns dazu erzwingen.

Danke.

War es hilfreich?

Lösung

Es ist tatsächlich einfacher, Ihre Fragen zu beantworten, beginnend mit Frage 2.

Sie haben gefragt: 2. Da die Ausnahmebehandler -Ausnahmereferenz mit der Ausnahme der Ausnahme ausgesetzt sein könnte, besteht keine Notwendigkeit, die Methode G () die geworfenbare Ausnahme auszulösen. Der Java -Compiler würde uns jedoch dazu erzwingen.

ANTWORT: Tatsächlich kann (Ausnahme E) kein Wurfgeschoss fangen. Versuche dies:

try {
       Throwable t = new Throwable();
       throw t.fillInStackTrace();
} catch (Exception e) {
    System.out.println("outer exception handler");
    e.printStackTrace();
} 

Sie werden sehen, dass die Fangklausel den Wurf in diesem Fall nicht fängt.

Der Grund, warum die Fangklausel in Ihrer g () -Methode funktioniert throw e.fillInStackTrace(), Der Anruf zum FillInstacktrace gibt tatsächlich eine Ausnahme zurück (das liegt daran, dass E selbst eine Ausnahme ist). Da die Ausnahme eine Unterklasse von Throwable ist, widerspricht dies der Erklärung der Fillinstacktrace nicht.

Nun zur ersten Frage

Sie haben gefragt: 1. Da Ausnahme.FillinStacktrace () Rückgabe -Throwable Referenz, sollte der Ausnahmehandler, der Ausnahmereferenz erhalten, die Ausnahme nicht aufnehmen können. Weil Java nicht zulässt, dass impliziten Downcast so etwas wie Rückgabe (Ausnahme) sein sollte. fillInstacktrace ().

Antwort: Dies ist nicht gerade ein implizites Downcast. Stellen Sie sich dies als eine Variation der Überlastung vor.

Nehmen wir an, Sie haben

void process(Throwable t){
   ...
}
void process(Exception e){
  ...
} 

Wenn Sie anrufen process(someObject), Es wird zur Laufzeit festgelegt, ob die erste oder die zweite Prozessmethode aufgerufen wird. In ähnlicher Weise kann die Fangklausel (Ausnahme E) Ihren Wurf zur Laufzeit erfassen oder nicht, basierend darauf, ob Sie eine Ausnahme oder Throwable ausgeben.

Andere Tipps

Ich bin ziemlich verwirrt von Ihrer Frage. Es gibt eindeutig etwas an Java -Ausnahmen / Ausnahmebehandlung, das Sie nicht verstehen. Beginnen wir also am Anfang.

In Java sind alle Ausnahmen (in dem Sinne, dass dieser Begriff in der Java -Sprachspezifikation verwendet wird) Instanzen einer Klasse, die eine Unterklasse von ist java.lang.Throwable. Es gibt zwei (und nur zwei) direkte Unterklassen von Throwable; dh java.lang.Exception und java.lang.Error. Instanzen all dieser Klassen ... einschließlich Fälle von Throwable und Irrtum ... werden als Ausnahmen in der JLS bezeichnet.

Ein Ausnahmebehandler fängt Ausnahmen (im JLS -Sinne), die mit dem in der verwendeten Ausnahmetyp kompatibel sind catch Erklärung. Also zum Beispiel:

try {
    ....
} catch (Exception ex) {
    ...
}

wird jede Ausnahme in die bekommen try Block, das eine Instanz von ist java.lang.Exception oder eines direkten oder indirekten Subtyps von java.lang.Exception. Aber es wird keine Instanz von fangen java.lang.Throwable, weil das (offensichtlich) nicht eines der oben genannten ist.

Auf der anderen Seite:

try {
    ....
} catch (Throwable ex) {
    ...
}

Wille fangen eine Instanz von java.lang.Throwable.

Wenn Sie Ihr Beispiel im Lichte dessen überprüfen, ist es offensichtlich, warum die f Die Methode fängt nicht die Throwable -Instanz ein: Sie stimmt nicht mit dem Ausnahmetyp in der Fangklausel überein! Dagegen in der g Methode Die Ausnahmeinstanz stimmte mit dem Ausnahmetyp in der Fangklausel überein und wird daher gefangen.

Ich verstehe nicht, was Sie sagen, um ein Throwable in zu werfen g. Erstens wird die Tatsache, dass die Methode erklärt, dass sie Wurfweise wirft nicht meine, dass es tatsächlich werfen muss. Alles was es sagt ist, dass es könnte Wirf etwas zuzugeworfenem Throwable ... möglicherweise in einer zukünftigen Version der g Methode. Zweitens, wenn Sie hinzufügen würden throw e; zum äußeren Fangblock, es möchten Werfen Sie etwas, das Throwable zugeordnet ist.

Schließlich ist es im Allgemeinen eine schlechte Idee, Instanzen von Throwable, Ausnahme, Irrtum und RunTimeException zu erstellen. Und Sie müssen sehr vorsichtig sein, wann und wie Sie sie fangen. Zum Beispiel:

try {
     // throws an IOException if file is missing
    InputStream is = new FileInputStream("someFile.txt");
    // do other stuff
} catch (Exception ex) {
    System.err.println("File not found");
    // WRONG!!!  We might have caught some completely unrelated exception;
    // e.g. a NullPointerException, StackOverflowError, 
}

BEARBEITEN - als Antwort von OPs Kommentaren:

Aber was ich mit Wurf E. fillinstacktrace () werfen; Sollte eine Intance von Throwable, nicht Ausnahme sein!

Das Javadoc sagt ausdrücklich, dass das zurückgegebene Objekt das Ausnahmungsobjekt ist, auf das Sie die Methode aufrufen. Der Zweck der fillInStacktrace() Die Methode besteht darin, die Stapelspur für ein vorhandenes Objekt auszufüllen. Wenn Sie eine andere Ausnahme wünschen, sollten Sie verwenden new Einen erstellen.

Eigentlich meine ich, dass der Outter -Ausnahmehandler den geworfenen Wurf nicht erfassen sollte, der E. fillinStacktrace () geworfen hat.

Ich habe erklärt, warum es so ist - weil das Throwable tatsächlich die ursprüngliche Ausnahme ist. Gibt es etwas an meiner Erklärung, das Sie nicht verstehen oder einfach sagen, dass Ihnen die Art und Weise, wie Java definiert ist, nicht gefällt?

Bearbeiten 2

Und wenn der Outter -Ausnahmebehandler mit der geworfenen Ausnahme ausgehen könnte, warum müssen wir dann angeben, dass die Methode g die Throwable -Ausnahme auswerfen würde

Sie verstehen falsch, was ich gesagt habe ... was war, dass wenn Sie eine Ausnahme gemacht haben, dann die throws Throwable wäre nicht überflüssig. Otoh, ich denke endlich, ich verstehe deine Beschwerde.

Ich denke, der Kern Ihrer Beschwerde ist, dass Sie damit einen Kompilierungsfehler erhalten:

public void function() throws Exception {
    try {
        throw new Exception();
    } catch (Exception ex) {
        throw ex.fillInStackTrace();
        // according to the static type checker, the above throws a Throwable
        // which has to be caught, or declared as thrown.  But we "know" that the 
        // exception cannot be anything other than an Exception.
    }
}

Ich kann sehen, dass dies etwas unerwartet ist. Aber ich fürchte, es ist unvermeidlich. Es gibt keine Möglichkeit (eine große Änderung des Java -Typsystems), dass Sie die Signatur des fillInStacktrace Das wird in allen Fällen funktionieren. Wenn Sie beispielsweise die Erklärung der Methode in die Ausnahmeklasse übertragen haben, würden Sie das gleiche Problem mit Subtypen der Ausnahme wiederholen. Wenn Sie jedoch versucht haben, die Signatur mit einem generischen Typparameter auszudrücken, würde dies dazu führen, dass alle Unterklassen von wirklich expliziten generischen Typen hergestellt werden.

Glücklicherweise ist die Heilung wirklich einfach; wirken das Ergebnis von fillInStacktrace() folgendermaßen:

public void function() throws Exception {
    try {
        throw new Exception();
    } catch (Exception ex) {
        throw (Exception) (ex.fillInStackTrace());
    }
}

Und der letzte Punkt ist, dass es sehr ungewöhnlich ist, dass eine Bewerbung explizit anrufen kann fillInStacktrace(). Vor diesem Hintergrund hätte es sich einfach nicht gelohnt, dass die Java -Designer ihren Eingeweide "gebrochen" haben, um dies zu lösen. Zumal es wirklich nur eine kleine Unannehmlichkeit ist ... höchstens.

Ich denke, Sie müssten Frank Yellin (die @author von java.lang.Exception). Wie andere gesagt haben, fillInStackTrace() wird deklariert in Throwable und dokumentiert, um zurückzukehren this, also muss sein Rückgabetyp sein Throwable. Es wird nur von geerbt von Exception. Frank hätte es überschreiben können Exception, so was:

public class Exception extends Throwable{
    /**Narrows the type of the overridden method*/
    @Override
    public synchronized Exception fillInStackTrace() {
        super.fillInStackTrace();
        return this;
    }
}

... aber er tat es nicht. Vor Java 1.5 ist der Grund dafür, dass es einen Kompilierungsfehler erzeugt hätte. In 1,5 und darüber hinaus kovariante Rückgabetypen sind erlaubt Und das oben oben ist legal.

Aber ich vermute, wenn es die obige Überschreibung existierte, würden Sie dann fragen, warum RuntimeException hat keine ähnliche Überschreibung, warum ArrayStoreException Überschreibt diese Überschreibung nicht und so weiter. Also wollten Frank und Freunde wahrscheinlich nicht diese Hunderte von identischen Überschreibungen schreiben.

Es ist erwähnenswert, dass Sie das, wenn Sie mit Ihren eigenen benutzerdefinierten Ausnahmegementen zu tun haben, das problemlos überschreiben können fillinStackTrace() Methode wie ich oben getan habe, und erhalten Sie den schmaleren Typ, nach dem Sie suchen.

Mit Generika könnte man sich vorstellen, die Erklärung von zu erweitern Throwable zu:

public class Throwable<T extends Throwable<T>>{
    public synchronized native T fillInStackTrace();
}

... aber das ist nicht wirklich zufriedenstellend, aus Gründen, die über den Rahmen dieser Antwort hinausgehen.

fillInStackTrace Gibt den Verweis auf dasselbe Objekt zurück. Es ist Methodekett Exception und Stapelspur der Ausnahme zurückzusetzen.

public static void m() {
    throw new RuntimeException();

}

public static void main(String[] args) throws Throwable {
    try {
        m();
    } catch (Exception e) {
        e.printStackTrace();
        throw e.fillInStackTrace();
    }
}

Der Methode -Rückgabe -Typ kann nur der Basistyp sein, der ist Throwable. Es kann so generiert werden, dass die Methode den parametrisierten Typ zurückgibt. Aber das ist vorerst nicht der Fall.

RuntimeException e = new RuntimeException();
Throwable e1 = e.fillInStackTrace();
System.out.println(e1.getClass().getName()); //prints java.lang.RuntimeException
System.out.println(e == e1); //prints true

fillInStackTrace() wird definiert von Throwable, nicht Exception.

Nicht alle Unterklassen von Throwable sind Ausnahmen (Error, zum Beispiel). So weit wie Throwable ist besorgt, das einzige, was es über den Rückgabewert von garantieren kann fillInStackTrace() ist, dass es eine Instanz von ist Throwable (Da es nur das gleiche Objekt zurückgibt wie Chandra Patni notiert).

Eigentlich fillInStackTrace Gibt das gleiche Objekt zurück, auf das es aufgerufen wurde.

e.fillInStackTrace == e ist immer wahr

Es ist nur ein Abkürzung, Sie können auch einfach schreiben

    } catch (Exception e) {
        System.out.println("inner exception handler");
        e.fillInStackTrace();
        throw e;
    }

oder verwenden Sie eine Besetzung

    throw (Exception) e.fillInStackTrace();

Übrigens passiert das gleiche mit initCause().

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top