Wann eine Zusicherung verwendet werden soll und wann eine Ausnahme verwendet werden soll

121

Die meiste Zeit werde ich eine Ausnahme verwenden, um nach einer Bedingung in meinem Code zu suchen. Ich frage mich, wann es ein angemessener Zeitpunkt ist, eine Behauptung zu verwenden.

Zum Beispiel,

Group group=null;
try{
    group = service().getGroup("abc");
}catch(Exception e){
    //I dont log error because I know whenever error occur mean group not found
}

if(group !=null)
{
    //do something
}

Können Sie angeben, wie eine Behauptung hier hineinpasst? Soll ich eine Behauptung verwenden?

Es scheint, als würde ich niemals Zusicherungen im Produktionscode verwenden und nur Zusicherungen in Komponententests sehen. Ich weiß, dass ich in den meisten Fällen nur Ausnahmen verwenden kann, um die Prüfung wie oben durchzuführen, aber ich möchte wissen, wie dies "professionell" angemessen durchgeführt werden kann.

Cometta
quelle

Antworten:

81

Assertions sollten verwendet werden, um etwas zu überprüfen, das niemals passieren sollte, während eine Ausnahme verwendet werden sollte, um etwas zu überprüfen, das passieren könnte.

Beispielsweise kann eine Funktion durch 0 geteilt werden, sodass eine Ausnahme verwendet werden sollte. Mit einer Zusicherung kann jedoch überprüft werden, ob die Festplatte plötzlich verschwindet.

Eine Zusicherung würde die Ausführung des Programms stoppen, eine Ausnahme würde jedoch dazu führen, dass das Programm weiter ausgeführt wird.

Beachten Sie, dass dies if(group != null)keine Behauptung ist, sondern nur eine Bedingung.

Marius
quelle
3
"Eine Zusicherung könnte verwendet werden, um zu überprüfen, ob die Festplatte plötzlich verschwindet" - Ich würde sagen, dass dies nicht korrekt ist: Warum sollte dies während der Entwicklung behandelt werden, aber nicht in der Produktion (wenn Zusicherungen normalerweise deaktiviert sind)?
Hermann
71
Der Kommentar zur Festplatte ist falsch. Assertions dienen zur Überprüfung auf Fehler in Ihrer Codelogik. Verwenden Sie sie niemals, um etwas zu überprüfen, das Sie nicht kontrollieren. Denken Sie daran, wenn eine Behauptung fehlschlägt, bedeutet dies, dass Ihr Code falsch ist .
Ian Goldby
1
@Marius Ihre Bedingung könnte durch eine Behauptung wie diese ersetzt werden: assert group! = Null
IgorGanapolsky
1
Downvoted, weil das Festplattenbeispiel Ihrer eigenen Philosophie widerspricht. Festplatten "verschwinden" (aus der Sicht des Codes) könnten tatsächlich in der Realität passieren - egal wie unwahrscheinlich. Wie @IanGoldby sagt, sollten Behauptungen nur von Dingen abhängen, die von Ihrem Code gesteuert werden.
Vicky Chijwani
Eine viel bessere Antwort, wenn sie von Gregory Pakosz gepostet wurde, lesen Sie bitte diesen Beitrag.
Ormurin
169

Aus meinem Kopf (die Liste ist möglicherweise unvollständig und zu lang, um in einen Kommentar zu passen) würde ich sagen:

  • Verwenden Sie Ausnahmen, wenn Sie Parameter überprüfen, die an öffentliche oder geschützte Methoden und Konstruktoren übergeben werden
  • Verwenden Sie Ausnahmen, wenn Sie mit dem Benutzer interagieren oder wenn Sie erwarten, dass sich der Clientcode von einer Ausnahmesituation erholt
  • Verwenden Sie Ausnahmen, um auftretende Probleme zu beheben
  • Verwenden Sie Assertions, wenn Sie Vorbedingungen, Nachbedingungen und Invarianten von privatem / internem Code überprüfen
  • Verwenden Sie Behauptungen, um sich selbst oder Ihrem Entwicklerteam Feedback zu geben
  • Verwenden Sie Behauptungen, wenn Sie nach Dingen suchen, die sehr unwahrscheinlich sind. Andernfalls bedeutet dies, dass Ihre Anwendung einen schwerwiegenden Fehler aufweist
  • Verwenden Sie Behauptungen, um Dinge zu erklären, von denen Sie (angeblich) wissen, dass sie wahr sind

Mit anderen Worten, Ausnahmen betreffen die Robustheit Ihrer Anwendung, während Zusicherungen deren Richtigkeit betreffen.

Behauptungen sind so konzipiert, dass sie billig zu schreiben sind. Sie können sie fast überall verwenden, und ich verwende diese Faustregel: Je mehr eine Behauptung dumm aussieht, desto wertvoller ist sie und desto mehr Informationen werden eingebettet. Wenn Sie ein Programm debuggen, das sich nicht richtig verhält, werden Sie anhand Ihrer Erfahrung sicherlich die offensichtlicheren Fehlermöglichkeiten prüfen. Dann werden Sie nach Problemen suchen, die einfach nicht auftreten können: Genau hier helfen Behauptungen viel und sparen Zeit.

Gregory Pakosz
quelle
53
Ich mag die Art und Weise, wie Sie dies formuliert haben: Ausnahmen betreffen die Robustheit Ihrer Anwendung, während Behauptungen die Richtigkeit betreffen .
M. Dudley
Ich habe dies auf meiner Website gepostet: pempek.net/articles/2013/11/16/assertions-or-exceptions
Gregory Pakosz
Und wenn Sie zufällig nach einer benutzerdefinierten C ++
Assert-
15

Generell:

  • Verwenden Sie Zusicherungen für interne Konsistenzprüfungen, bei denen es überhaupt nicht darauf ankommt, ob jemand sie ausschaltet. (Beachten Sie, dass der javaBefehl standardmäßig alle Zusicherungen deaktiviert.)
  • Verwenden Sie regelmäßige Tests für jede Art von Überprüfung, was nicht ausgeschaltet werden sollte. Dies umfasst Abwehrprüfungen, die vor möglichen Schäden durch Fehler schützen, sowie Validierungsdaten / -anforderungen / was auch immer von Benutzern oder externen Diensten bereitgestellt wird.

Der folgende Code aus Ihrer Frage ist schlecht und möglicherweise fehlerhaft

try {
    group = service().getGroup("abc");
} catch (Exception e) {
    //i dont log error because i know whenever error occur mean group not found
}

Das Problem ist, dass Sie NICHT wissen, dass eine Ausnahme bedeutet, dass die Gruppe nicht gefunden wurde. Es ist auch möglich, dass der service()Aufruf eine Ausnahme nullausgelöst hat oder zurückgegeben wurde, was dann eine verursachte NullPointerException.

Wenn Sie eine "erwartete" Ausnahme abfangen, sollten Sie nur die erwartete Ausnahme abfangen . Indem java.lang.ExceptionSie das Problem abfangen (und insbesondere nicht protokollieren), erschweren Sie die Diagnose / Fehlerbehebung des Problems und ermöglichen der App möglicherweise, mehr Schaden anzurichten.

Stephen C.
quelle
4

Zurück bei Microsoft war die Empfehlung, Ausnahmen in alle APIs zu werfen, die Sie öffentlich zur Verfügung stellen, und Asserts in allen möglichen Annahmen zu internem Code zu verwenden. Es ist eine etwas lockere Definition, aber ich denke, es liegt an jedem Entwickler, die Grenze zu ziehen.

In Bezug auf die Verwendung von Ausnahmen sollte deren Verwendung, wie der Name schon sagt, außergewöhnlich sein. Für den oben angegebenen Code getGroupsollte der Aufruf zurückgegeben werden, nullwenn kein Dienst vorhanden ist. Eine Ausnahme sollte nur auftreten, wenn eine Netzwerkverbindung unterbrochen wird oder ähnliches.

Ich denke, die Schlussfolgerung ist, dass es für jede Anwendung etwas dem Entwicklungsteam überlassen bleibt, die Grenzen von Assert gegen Ausnahmen zu definieren.

rui
quelle
IMHO ist das Problem mit dieser Art von Empfehlung, dass es in Ordnung ist, solange die Grenze zwischen dem öffentlichen und dem privaten Teil einer API ziemlich fest ist. Wenn Sie neuen Code entwickeln, ist diese Grenze oft ziemlich fließend ...
Len Holgate
Ja, du hast Recht. Es ist eine Richtlinie, aber am Ende des Tages wird sie der Sensibilität des Programmierers überlassen. Ich glaube nicht, dass es eine ultimative definierende Linie für diese gibt, also denke ich, dass Sie einfach mit dem weitermachen, was Sie für richtig halten, wenn Sie viele verschiedene Codes lesen.
Rui
3

Laut diesem Dokument http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#design-faq-general "ist die assert-Anweisung für nicht öffentliche Vorbedingungen, Nachbedingungen und Klasseninvarianten geeignet Überprüfung. Die Überprüfung öffentlicher Vorbedingungen sollte weiterhin durch Überprüfungen innerhalb von Methoden durchgeführt werden, die insbesondere zu dokumentierten Ausnahmen führen, z. B. IllegalArgumentException und IllegalStateException. "

Wenn Sie mehr über Vorbedingungen, Nachbedingungen und Klasseninvarianten erfahren möchten, lesen Sie dieses Dokument: http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#usage-conditions . Es enthält auch Beispiele für die Verwendung von Behauptungen.

Cesarsalgado
quelle
1

Beim Testen auf Null werden nur Nullen abgefangen, die Probleme verursachen, während bei einem Versuch / Fang, wie Sie ihn haben, alle Fehler abgefangen werden .

Im Allgemeinen ist try / catch sicherer, aber etwas langsamer, und Sie müssen darauf achten, dass Sie alle Arten von Fehlern abfangen, die auftreten können. Ich würde also sagen, benutze try / catch - eines Tages könnte sich der getGroup-Code ändern, und du brauchst möglicherweise nur dieses größere Netz.

Phil H.
quelle
1

Sie können diesen einfachen Unterschied während ihrer Verwendung berücksichtigen. Ausnahmen werden zum Überprüfen erwarteter und unerwarteter Fehler verwendet, die als geprüfter und nicht aktivierter Fehler bezeichnet werden, während die Zusicherung zur Laufzeit hauptsächlich zu Debugging-Zwecken verwendet wird, um festzustellen, ob die Annahmen validiert sind oder nicht.

SBTec
quelle
1

Ich gebe zu, ich bin ein wenig verwirrt von Ihrer Frage. Wenn eine Assertionsbedingung nicht erfüllt ist, wird eine Ausnahme ausgelöst. Verwirrenderweise wird dies AssertionError genannt . Beachten Sie, dass das Kontrollkästchen deaktiviert ist, z. B. IllegalArgumentException, die unter sehr ähnlichen Umständen ausgelöst wird.

Verwenden Sie also Assertions in Java

  1. ist ein präziseres Mittel zum Schreiben eines Bedingungs- / Wurfblocks
  2. Ermöglicht das Ein- und Ausschalten dieser Prüfungen über JVM-Parameter. Normalerweise würde ich diese Überprüfungen die ganze Zeit belassen, es sei denn, sie wirken sich auf die Laufzeitleistung aus oder haben eine ähnliche Strafe.
Brian Agnew
quelle
AssertionError ist eine Unterklasse von Error not RuntimeException.
Stephen C
Ah. Natürlich. Ich dachte an aktiviert / deaktiviert. Jetzt korrigiert
Brian Agnew
Es wird erklärt, was Behauptungen sind (aus kontroverser Sicht), aber nicht, wann sie genau verwendet werden müssen.
Karl Richter
1

Siehe Abschnitt 6.1.2 (Zusicherungen im Vergleich zu anderen Fehlercodes) in der Dokumentation von Sun unter dem folgenden Link.

http://www.oracle.com/technetwork/articles/javase/javapch06.pdf

Dieses Dokument gibt den besten Rat, den ich gesehen habe, wann Behauptungen verwendet werden sollen. Zitat aus dem Dokument:

"Eine gute Faustregel ist, dass Sie eine Behauptung für Ausnahmefälle verwenden sollten, die Sie vergessen möchten. Eine Behauptung ist der schnellste Weg, um mit einer Bedingung oder einem Zustand umzugehen und diese zu vergessen, die Sie nicht erwarten müssen Zurecht kommen."

Phil
quelle
0

Asserts können leider deaktiviert werden. Wenn Sie in der Produktion sind, brauchen Sie alle Hilfe, die Sie bekommen können, um etwas Unvorhergesehenes aufzuspüren.

Thorbjørn Ravn Andersen
quelle