Wirfst du eine argumentexception oder argumentnullexception aus privaten Methoden?

20

Ich habe gerade einen Code durchgesehen, den ich vor einiger Zeit geschrieben habe, und habe festgestellt, dass ich einige private Methoden habe, die argumentnullexceptions und / oder argumentexceptions auslösen, wenn es Probleme mit den Methodenparametern gibt.

Ich vermute, meine Überlegung ist, dass dies der Zukunftssicherheit der Anwendung hilft, wenn jemand versucht, die Methode in Zukunft zu "missbrauchen". Da es sich jedoch um eine private Methode handelt und die Leute, die diese Methode wahrscheinlich aufrufen, die zugehörigen Kommentare und den Code sehen können, ist es nur unnötig, diese zu werfen. Es tut sicher nicht weh, sie zu haben, obwohl es Unordnung hinzufügt.

Ich bin der Meinung, dass diese Ausnahmen bei einer API, die öffentlich verfügbar gemacht wird, im Allgemeinen nützlicher sind.

Herr Elch
quelle

Antworten:

22

Normalerweise werden bei privaten Methoden keine Ausnahmen ausgelöst, da der Entwickler beim Schreiben wissen muss, wie und woher er die Methode aufruft. Daher sollten die als Parameter an die private Methode übergebenen Variablen außerhalb der Methode, dh vor dem Aufruf, überprüft werden. Das Auslösen von "InvalidArgumentException" und anderen derartigen Ausnahmen wird als bewährte Methode für öffentliche Methoden angesehen (unabhängig davon, ob Sie eine "API" schreiben oder nicht).

In den Fällen, in denen Sie "InvalidArgumentException" auslösen möchten, ist zu erwähnen, dass Assertdie Spring-API für Java seit Version 1.1.2 eine Klasse enthält. Zumindest für mich war es sehr hilfreich, weniger Code zu schreiben, um Überprüfungen durchzuführen.

Sie können jedoch "asserts" verwenden, um Parameter in privaten Methoden zu überprüfen. Das ist einer ihrer wahren Zwecke. Weitere Gründe für die Verwendung finden Sie unter dem folgenden Link, in dem auch ausführlich erläutert wird, wann Asserts und wann Ausnahmen verwendet werden. Asserts dürfen nicht im Produktionscode enthalten sein, und der Compiler entfernt sie standardmäßig. Sie sind also genau das, wonach Sie suchen: Sie helfen den Entwicklern, für die Benutzer unsichtbar. In Java müssen Sie ein spezielles Flag ("-ea") verwenden, um den Compiler anzuweisen, Assertions zu aktivieren. Sie können sie als "Debugging" -Freunde betrachten.

So verwenden Sie Asserts in:

Jalayn
quelle
1
Apache Commons hat auch eine Validate-Klasse, die ähnlich wie Spring's Assert-Klasse funktioniert
Rosa Richter
@cantido ja und ich würde auch hinzufügen, dass die Preconditions-Klasse in Googles Guava genauso funktioniert. Vielen Dank für die Information :-)
Jalayn
2

Wie alles andere kommt es darauf an ....

Wenn es sich bei den öffentlichen Methoden um einfache Wrapper handelt, die die private Methode aufrufen (im Sinne einer privaten überladenen Methode), ist es möglicherweise sinnvoll, eine Ausnahme in der privaten Methode auszulösen, anstatt jede öffentliche einzuchecken.

Im Allgemeinen würde ich die Argumente nicht überprüfen / eine Ausnahme für eine private Methode auslösen, wenn sie nicht der obigen Definition entspricht. Obwohl es andere Fälle gibt, mache ich dies im Allgemeinen in einer privaten Methode, bevor teure Operationen ausgeführt werden, die teilweise fehlschlagen können, wenn die Argumente ungültig sind.

Ken Henderson
quelle
2

Mir ist klar, dass die Frage zwar kein Sprachkennzeichen hat, aber wahrscheinlich implizit von „Kaffeesprachen“ handelt. Der Vollständigkeit halber möchte ich jedoch den etwas divergierenden offensichtlichen Konsens in der C ++ - Welt erwähnen.

Es gibt drei Dinge, die C ++ - Programmierer normalerweise interessieren:

  • Wird es bei optimierten Builds keinen Overhead geben? (Das heißt, kann es "kompiliert" werden?)
  • Kann ich damit genau an der Stelle, an der der Fehler festgestellt wurde, einen Debugger einfangen?
  • Kann ich damit Probleme von deklarierten Funktionen melden noexcept?

In der Vergangenheit habe ich das erste Problem gelöst, indem ich Code wie diesen geschrieben habe

int
factorial(const int n)
{
  if (CHECK_ARGS)
    {
      if (n < 0)
        throw std::invalid_argument {"n < 0"};
    }
  int fac = 1;
  for (int i = 2; i <= n; ++i)
    fac *= i;
  return fac;
}

Dabei CHECK_ARGSist #defined eine Konstante für die Kompilierungszeit, damit der Compiler den gesamten Code für die Argumentprüfung in optimierten Builds vollständig eliminieren kann. (Ich sage nicht, dass das Kompilieren der Checks im Allgemeinen eine gute Sache ist, aber ich glaube, dass ein Benutzer die Option haben sollte , sie zu kompilieren.)

Ich mag immer noch an dieser Lösung, dass der Code zur Überprüfung des Arguments deutlich sichtbar ist und sich in der gruppiert if. Das zweite und dritte Problem werden dadurch jedoch nicht gelöst. Daher neige ich jetzt wieder mehr dazu, ein assertMakro zur Argumentprüfung zu verwenden.

Die Boost-Codierungsstandards stimmen dem zu:

Was ist mit Programmierfehlern?

Wenn ich als Entwickler gegen eine Vorbedingung einer Bibliothek verstoßen habe, die ich verwende, möchte ich nicht, dass sich der Stapel auflöst. Was ich möchte, ist ein Core-Dump oder ähnliches - eine Möglichkeit, den Status des Programms genau an dem Punkt zu überprüfen, an dem das Problem erkannt wurde. Das heißt normalerweise assert()oder so ähnlich.

Auf der CppCon'14 hielt John Lakos einen sehr interessanten Vortrag mit dem Titel Defensive Programming Done Right ( Teil 1 , Teil 2) ). Im ersten Teil seines Vortrags diskutiert er die Theorie der Verträge und des undefinierten Verhaltens. Im zweiten Teil stellt er einen meiner Meinung nach sehr guten Vorschlag zur systematischen Argumentationsprüfung vor. Im Wesentlichen schlägt er Assertion-Makros vor, mit denen der Benutzer auswählen kann, wie viel eines Budgets (in Bezug auf die CPU-Auslastung) er der Bibliothek zur Überprüfung von Argumenten spenden möchte, und die Bibliothek veranlasst, dieses Budget sinnvoll zu nutzen. Zusätzlich kann der Benutzer eine globale Fehlerbehandlungsfunktion installieren, die aufgerufen wird, wenn ein defekter Vertrag festgestellt wird.

In Bezug auf den Aspekt, dass eine Funktion privat ist, glaube ich nicht, dass dies bedeutet, dass wir sie niemals ihre Argumente überprüfen lassen sollten . Wir können uns eher darauf verlassen, dass unser eigener Code den Vertrag einer internen Funktion nicht verletzt, aber wir wissen auch, dass wir auch nicht perfekt sind. Das Überprüfen von Argumenten in internen Funktionen ist für das Erkennen eigener Fehler genauso hilfreich wie für öffentliche Funktionen zum Erkennen von Fehlern im Client-Code.

5gon12eder
quelle
1

Betrachten Sie die folgende Struktur:

  1. Interne Logik: Diese Funktion setzt voraus, dass sie mit korrekten Parametern aufgerufen wird, und verwendet daher Asserts, um Vorbedingungen, Nachbedingungen und Invarianten zu überprüfen, um Ihre innere Logik zu überprüfen.

  2. Benutzeroberfläche Wrapper: Diese Funktion wickelt die interne Funktion und nutzt InvalidArgumentExceptions falsche Werte zu handhaben und dem Benutzer zu sagen , seine Eingaben zu korrigieren: Assert(x).hasLength(4);, Assume(y).isAlphanumeric();, Assert(z).isZipCode();, Assume(mailAdress).matchesRegex(regex_MailAdress);, Reject(x).ifEmpty();, usw.

  3. Batch-Interface-Wrapper: Diese Funktion umschließt die interne Funktion und verwendet Protokollierung, Gültigkeitsmarkierungen und Statistiken, um falsche Werte zu verarbeiten, ohne eine lang laufende Aufgabe zu unterbrechen. Die Markierungen könnten später von jemandem verwendet werden, der die Ergebnisdatenbank überprüft und säubert.

  4. Command Line Interface Wrapper: Diese Funktion bricht die interne Funktion um und fragt erneut nach der letzten Eingabe.

Sie sollten beide Methoden - Asserts und Exceptions - für verschiedene Aufgaben verwenden. Sie sollten die interne Logik von der Parameterprüfung trennen. Vergleichen Sie dies mit der Trennung von Modell, Ansicht und Steuerung.

Ralf K.
quelle
0

Es gibt bessere Möglichkeiten, eine Nullreferenzprüfung zu vermeiden: Verwenden Sie einen Codevertrag oder ein AOP-Framework, um die Prüfung für Sie durchzuführen. Google "C # -Code-Vertrag" oder "Postsharp".

Kodismus
quelle
Ich denke, meine Frage würde sich auch auf Code-Verträge erstrecken. Müssen bei einer privaten Methode die Methodenvoraussetzungen überprüft werden (z. B. für zukünftige Prüfungen oder um Sie daran zu hindern, sich in den Fuß zu schießen)?
Mr Moose