Frage

Java können Sie einen völlig neuen Subtyp von Throwable erstellen, z:

public class FlyingPig extends Throwable { ... }

sehr selten , ich etwas tun kann:

throw new FlyingPig("Oink!");

und natürlich an anderer Stelle:

try { ... } catch (FlyingPig porky) { ... }

Meine Fragen sind:

  • Ist das eine schlechte Idee? Und wenn ja, warum?
    • Was getan werden könnte dieses Subtyping zu verhindern, wenn es eine schlechte Idee ist?
    • Da es nicht vermeidbar ist (soweit ich weiß), welche Katastrophen führen könnte?
  • Ist dies nicht so eine schlechte Idee ist, warum nicht?
    • Wie kann man etwas Nützliches aus der Tatsache, dass Sie extends Throwable können?

Vorgeschlagene Szenario # 1

Ein Szenario, in dem ich war wirklich versucht, etwas zu tun, wie dies die folgenden Eigenschaften hat:

  • Das "Ereignis" ist etwas, das wird schließlich passieren. Es ist erwartet . Es ist auf jeden Fall kein Error, und es gibt nichts Exception-al etwa, wenn er auftritt.
    • Weil es ist zu erwarten: , wird es eine catch darauf gewartet werden. Es wird nicht „slip“ Vergangenheit nichts. Es wird nicht „Flucht“ aus jedem Versuch catch allgemeinen Exception und / oder Error.
  • Das "Ereignis" geschieht extrem selten .
  • Wenn es passiert, in der Regel gibt es einen tiefen Stack-Trace.

So vielleicht klar, es ist jetzt, was ich versuche zu sagen:. FlyingPig ist das Ergebnis eine erschöpfenden rekursive Suche

Das Objekt durchsucht werden existiert: Es ist nur eine Frage die es im großen Meer zu finden, die der Suchraum ist. Der Suchprozess wird ein langer sein, so dass die relativ hohen Kosten der Ausnahmebehandlung vernachlässigbar ist. In der Tat kann teurer sein die traditionelle Steuerfluss Konstrukt Alternative eine boolean isFound Flagge zu verwenden, da es kontinuierlich während des Suchprozesses überprüft werden muss, höchstwahrscheinlich auf jeder Ebene der Rekursion. Diese Prüfung wird 99,99% der Zeit ausfallen, aber es ist absolut notwendig, um die Abbruchbedingung zu propagieren. In einer Art und Weise, während wirksam , die Prüfung ist ineffizient

Durch einfache throw-ing eines FlyingPig wenn das gesuchte Objekt gefunden wird, müssen Sie nicht mit der Verwaltung des boolean isFound Flagge den Code Krempel. Nicht nur ist der Code sauberer in dieser Hinsicht, aber es kann schneller durch diese Auslassung ausgeführt werden.

Um es zusammenzufassen, ist die Wahl zwischen diesen beiden:

  • Traditioneller Steuerfluss Ansatz
    • Verwenden Sie ein boolean isFound, überprüft kontinuierlich
    • 99,99% der Zeit, ist die Prüfung ein „Abfall“, weil es immer noch false
    • würde
    • Wenn es schließlich true wird, stoppen Sie Rekursion und Sie müssen sicherstellen, dass Sie richtig Abwickler an den ersten Anruf.
  • FlyingPig Ansatz
    • Nicht mit boolean isFound stören.
    • Wenn Sie gefunden werden, nur throw new FlyingPig(); es erwartet , so wird es eine catch für sie.
    • Keine Verwaltung von boolean Flagge, keine verschwendete überprüfen, ob Sie brauchen, um weiterzumachen, keine Buchhaltung manuell Abwickler die Rekursion, etc.

Fragen:

  • Ist diese Technik von (ab) mit Ausnahme gültig? (Gibt es einen Namen dafür?)
  • Wenn gültig, sollte FlyingPig extends Throwable, oder ist Exception ganz gut? (Obwohl es gibt nichts außergewöhnliches über seine Verhältnisse?)
War es hilfreich?

Lösung

Ich würde sagen, dass es eine wirklich schlechte Idee ist. Viele Code basiert auf der Annahme durchgeführt, dass, wenn Sie Error und Exception fangen Sie haben alle möglichen Ausnahmen gefangen. Und die meisten Tutorials und Lehrbücher werden Ihnen sagen, die gleiche Sache. Durch eine direkte Unterklasse von Throwable Erstellen Sie möglicherweise alle Arten von Wartungs- und Interoperabilitätsprobleme schaffen.

kann ich keinen guten Grund denken Throwable zu verlängern. Verlängern Exception oder RuntimeException statt.

Bearbeiten -. Als Reaktion auf die vorgeschlagene Szenario der OP # 1

Ausnahmen sind eine sehr teuere Art und Weise mit „normaler“ Flusskontrolle umzugehen. In einigen Fällen sprechen wir Tausende zusätzliche Befehle ausgeführt zu erstellen, werfen und eine Ausnahme zu fangen. Wenn Sie akzeptiert Weisheit und die Verwendung von Ausnahmen für nicht-außergewöhnliche Flusskontrolle ignorieren will, verwenden Sie einen Exception Subtyp. etwas ist ein „Event“ nicht eine „Ausnahme“, indem er erklärt ist als ein Subtyp von Throwable, so zu tun versuchen, ist nichts zu erreichen gehen.

Allerdings ist es ein Fehler, eine Ausnahme mit einem Fehler, Fehler, falsch zu verschmelzen, was auch immer. Und es ist nichts falsch mit was einem „außergewöhnlichen Ereignis, das nicht ein Fehler ist, Fehler, falsch, oder was auch immer“ eine Unterklasse von Exception verwenden. Der Schlüssel ist, dass die Veranstaltung sein sollte außergewöhnliche ; das heißt aus dem üblichen, geschieht sehr selten, ...

Insgesamt ein FlyingPig kann kein Fehler sein, aber das ist kein Grund, es nicht als Subtyp von Exception zu erklären.

Andere Tipps

Ist diese Technik von (ab) mit Ausnahme gültig? (Gibt es einen Namen dafür?)

Meiner Meinung nach, es ist keine gute Idee:

  • Es verletzt die Prinzip der geringsten Erstaunen , es den Code schwerer macht besonders zu lesen, wenn es nichts Ausnahme-al darüber.
  • Ausnahme Werfen ist eine sehr teuere Operation in Java (hier kein Problem, obwohl sein könnte).

Ausnahme sollte nur nicht für die Ablaufsteuerung verwendet werden. Wenn ich diese Technik zu nennen hätte, würde ich es nennt einen Code Geruch oder ein Anti-Muster.

Siehe auch:

Wenn gültig, sollte FlyingPig erstreckt Throwable oder Exception ist gut? (Obwohl es gibt nichts außergewöhnliches über seine Verhältnisse?)

Es kann Situationen geben, in denen Sie auf wollen Fang Throwable nicht nur fangen Exception , sondern auch Error aber es ist selten, Menschen in der Regel nicht fangen Throwable. Aber ich kann nicht eine Situation, bei der Suche nach, wo Sie möchten throw eine Unterklasse von Throwable.

Und ich denke auch, dass Throwable erstreckt macht die Sache nicht weniger aussehen „Ausnahme-al“ , sie machen es schlechter aussehen - was völlig die Absicht besiegt.

So schließen, wenn Sie wirklich etwas werfen wollen, eine Unterklasse von Exception werfen.

Siehe auch:

Hier ist ein Blog-Post von John Rose, ein Architekt HotSpot:

http://blogs.oracle.com/jrose/entry/longjumps_considered_inexpensive

Es handelt sich um „missbrauchen“ Ausnahmen für die Ablaufsteuerung. Etwas anders Anwendungsfall, aber .. Kurz gesagt, es funktioniert wirklich gut - wenn Sie vorbelegen / Klon Ihre Ausnahmen Stack-Traces zu verhindern, erstellt werden.

Ich denke, dass diese Technik vertretbar ist, wenn „versteckt“ von Kunden. IE, Ihre FlyingPig sollte nie in der Lage sein, Ihre Bibliothek (alle öffentlichen Methoden transitively garantieren sollte es nicht zu werfen) zu verlassen. Eine Möglichkeit, dies zu gewährleisten, wäre es eine geprüfte Ausnahme zu machen.

Ich denke, die einzige Rechtfertigung für Throwable erstreckt, ist, weil Sie wollen, damit die Menschen in Rückrufe zu übergeben, die catch (Exception e) Klauseln haben, und Sie möchten Ihr Ergebnis, indem sie ignoriert werden. Ich kann nur kaufen, um diese ...

Die org.junit.Test Annotation umfasst die Klasse, die None Throwable erstreckt und wird als der Standardwert für die Annotation expected Parameter verwendet wird.

Wenn Sie rechtfertigen können, was eine FlyingPig abgesehen von beiden Fehlern und Ausnahme, so dass es nicht geeignet als Unterklasse von entweder ist, dann gibt es nichts grundlegend falsch mit ihm zu schaffen.

Das größte Problem, das ich von ist in der pragmatischen Welt denken kann, manchmal gibt es berechtigte Gründe java.lang.Exception zu fangen. Ihre neue Art von throwable geht rechts vorbei Try-Catch-Blöcke fliegen, die jede vernünftige Erwartung der Unterdrückung hatte (oder Protokollierung, Verpackung, was auch immer) alle möglichen nicht-tödliche Problem.

Auf der anderen Seite, wenn Sie tun Wartung auf einem alten System, das ist un zu Recht unterdrückt java.lang.Exception, könnten Sie betrügen um ihn herum. (Vorausgesetzt, den aufrichtigen Appell für die Zeit, um tatsächlich zu beheben es richtig verweigert wird).

Da diese Frage entwickelt hat, ich sehe dass ich den Punkt der falsch verstanden ursprüngliche Frage, so das einige andere Antworten sind wahrscheinlich mehr relevant. Ich werde diese Antwort überlassen hier, um da es noch hilfreich sein andere, die eine ähnliche Frage haben, und findet diese Seite bei der Suche nach eine Antwort auf ihre Frage.

Es ist nichts falsch mit der Erweiterung Throwable der Lage sein, Ausnahmen zu werfen (und Griff) Brauch. Sie sollten jedoch die folgenden Punkte beachten:

  • Die meisten spezifische Ausnahme möglich ist, eine großartige Idee. Es ermöglicht dem Anrufer verschiedene Arten von Ausnahmen unterschiedlich zu behandeln. Die Klassenhierarchie der Ausnahme ist wichtig, im Auge zu behalten, so dass Ihre benutzerdefinierte Ausnahme eines andere Art von Throwable erstrecken sollte, die so nah an Ihre Ausnahme wie möglich.
  • Erweiterung Throwable möglicherweise zu hohen Ebene sein. Versuchen Sie erstreckt Exception oder Runtime statt (oder eine niedrigere Ebene Ausnahme, die näher an den Grunde ist, dass Sie eine Ausnahme werfen). Beachten Sie den Unterschied zwischen einem Runtime und eine Ausnahme.
  • Ein Aufruf einer Methode, die eine Exception (oder eine Unterklasse von Exception) wirft müssen in einem try / catch-Block eingewickelt werden, die den Umgang mit der Ausnahme der Lage ist. Das ist gut für Fälle, wenn man die Dinge erwarten, falsch zu gehen, aufgrund von Umständen, die von Ihrer Kontrolle heraus kann (zum Beispiel das Netzwerk ist nach unten).
  • Ein Aufruf einer Methode, die eine Runtime (oder eine Unterklasse davon) wirft braucht nicht in einem try / catch-Block gewickelt werden, der die Ausnahme behandeln kann. (Es könnte sicher sein, aber es muss nicht sein.) Das mehr für Ausnahmen, die wirklich nicht zu erwarten.

Also, nehme an, Sie folgende Ausnahmeklassen in Ihrer Codebasis haben:

public class Pig extends Throwable { ... }
public class FlyingPig extends Pig { ... }
public class Swine extends Pig { ... }
public class CustomRuntimeException extends RuntimeException { ... }

Und einige Methoden

public void foo() throws Pig { ... }
public void bar() throws FlyingPig, Swine { ... }
// suppose this next method could throw a CustomRuntimeException, but it
// doesn't need to be declared, since CustomRuntimeException is a subclass
// of RuntimeException
public void baz() { ... } 

Nun, könnten Sie einen Code haben, der diese Methoden wie diese Anrufe:

try {
    foo();
} catch (Pig e) {
    ...
}

try {
    bar();
} catch (Pig e) {
    ...
}

baz();

Beachten Sie, dass, wenn wir bar() nennen, können wir nur Pig fangen, da beide FlyingPig und Swine Pig verlängern. Dies ist nützlich, wenn Sie die gleiche Sache zu behandeln entweder Ausnahme machen wollen. Sie könnten jedoch behandeln sie anders:

try {
    bar();
} catch (FlyingPig e) {
    ...
} catch (Swine e) {
    ...
}

The Play! framework uses something like this for request handling. The request processing goes through many layers (routing, middleware, controllers, template rendering) and at the final layer the rendered HTML is wrapped in a throwable and thrown, which the top most layer catches, unwraps and sends to the client. So none of the methods in the many layers involved need to explicitly return a response object, nor do they need to have a response object passed as argument to be propagated and modified.

I am bit sketchy on details. You can look through the code of Play! framework for details.

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