Mit @Nonnull annotierte Parameter auf Null prüfen?

19

Wir haben damit begonnen, FindBugs zu verwenden und unsere Parameter mit den @Nonnullentsprechenden Anmerkungen zu versehen , und es ist großartig, früh im Zyklus auf Fehler hinzuweisen. Bisher haben wir diese Argumente weiterhin auf die nullVerwendung von Guava's checkNotNullüberprüft, aber ich würde es vorziehen, nullnur an den Rändern zu suchen - Stellen, an denen der Wert eingegeben werden kann, ohne auf z null. B. eine SOAP-Anfrage geprüft worden zu sein .

// service layer accessible from outside
public Person createPerson(@CheckForNull String name) {
    return new Person(Preconditions.checkNotNull(name));
}

...

// internal constructor accessed only by the service layer
public Person(@Nonnull String name) {
    this.name = Preconditions.checkNotNull(name);  // remove this check?
}

Ich verstehe, dass @Nonnullsich nullWerte nicht blockieren .

Da FindBugs jedoch darauf hinweist, dass irgendwo ein Wert von einem nicht markierten Feld in ein markiertes Feld übertragen wird @Nonnull, können wir uns nicht darauf verlassen, dass diese Fälle abgefangen werden (was auch immer der Fall ist), ohne dass diese Werte nullüberall überprüft werden müssen, wo sie herumgereicht werden das System? Bin ich naiv, wenn ich dem Tool vertrauen und diese ausführlichen Überprüfungen vermeiden möchte?

Fazit: Obwohl es sicher erscheint, den zweiten nullHaken unten zu entfernen , ist es eine schlechte Praxis?

Diese Frage ist vielleicht zu ähnlich wie Sollte man auf null prüfen, wenn er nicht null erwartet , aber ich frage speziell in Bezug auf die @NonnullAnmerkung.

David Harkness
quelle

Antworten:

6

Wenn Sie FindBug nicht vertrauen, kann es eine Option sein, eine Behauptung zu verwenden. Auf diese Weise vermeiden Sie die von User MSalters angesprochenen Probleme, haben aber dennoch eine Prüfung. Natürlich ist dieser Ansatz möglicherweise nicht anwendbar, wenn ein solcher Fail-Fast-Ansatz nicht durchführbar ist, dh Sie müssen eine Ausnahme abfangen.

Und um die Frage weiter zu beantworten, ob es sich um eine schlechte Praxis handelt. Nun, das ist fraglich, aber ich würde es nicht glauben. Ich betrachte diese FindBug-Annotation als eine Lichtspezifikation, die dem Prinzip des Vertragsentwurfs folgt.

In design by contract stellen Sie einen Vertrag zwischen einer Methode und ihrem Aufrufer her. Der Vertrag besteht aus Voraussetzungen, die der Aufrufer beim Aufruf der Methode zu erfüllen bereit ist, und einer Nachbedingung, die die Methode nach der Ausführung erfüllt, wenn ihre Voraussetzung erfüllt ist.

Einer der Vorteile dieser Entwicklungsmethode besteht darin, dass Sie einen sogenannten defensiven Programmierstil vermeiden können (bei dem Sie explizit nach allen ungültigen Parameterwerten suchen usw.). Stattdessen können Sie sich auf den Vertrag verlassen und redundante Überprüfungen vermeiden, um die Leistung und Lesbarkeit zu verbessern.

Verträge können für die Laufzeitüberprüfung von Assertions verwendet werden, die dem oben genannten Fail-First-Prinzip folgt, bei dem Sie möchten, dass Ihr Programm bei einem Vertragsbruch fehlschlägt. Auf diese Weise erhalten Sie einen Anhaltspunkt, um die Fehlerquelle zu identifizieren. (Eine fehlgeschlagene Vorbedingung bedeutet, dass der Aufrufer etwas falsch gemacht hat. Eine fehlgeschlagene Nachbedingung weist auf einen Implementierungsfehler der angegebenen Methode hin.)

Darüber hinaus können Verträge für statische Analysen verwendet werden, die Rückschlüsse auf den Quellcode ziehen, ohne ihn tatsächlich auszuführen.

Die Annotation @nonnull kann als Voraussetzung für die statische Analyse durch das Tool FindBugs angesehen werden. Wenn Sie einen Ansatz wie die Überprüfung der Laufzeit-Assertion bevorzugen, dh die Fail-First-Strategie, sollten Sie die Verwendung von Assertion-Anweisungen als integriertes Java in Betracht ziehen. Oder vielleicht, um sich an eine ausgefeiltere Spezifikationsstrategie anzupassen, indem Sie eine Sprache für die Verhaltensschnittstellenspezifikation wie die Java Modeling Language (JML) verwenden.

JML ist eine Erweiterung von Java, in die die Spezifikation in speziellen Java-Kommentaren eingebettet ist. Ein Vorteil dieses Ansatzes besteht darin, dass Sie eine ausgefeilte Spezifikation verwenden können, selbst wenn Sie einen Entwicklungsansatz verwenden, bei dem Sie sich nur auf die Spezifikation und nicht auf Implementierungsdetails verlassen und verschiedene Tools verwenden, die von der Spezifikation Gebrauch machen, z. automatische Erstellung von Unit-Tests oder Dokumentationen.

Wenn Sie meinen Standpunkt, dass @nonnull ein (leichter) Vertrag ist, teilen, ist es üblich, keine zusätzlichen Prüfungen hinzuzufügen, da die ursprüngliche Idee hinter diesem Prinzip darin besteht, defensive Programmierung zu vermeiden.

FabianB
quelle
2
Genau so benutze ich @Nonnull: als Vertragsspezifikation. Ich habe die defensiven Schecks hinter dem Vertrag entfernt und bis jetzt keine Probleme gehabt.
David Harkness
4

Überlegen Sie, warum Sie nicht schreiben

this.name = Preconditions.checkNotNull(name);  // Might be necessary
that.name = Preconditions.checkNotNull(this.name);  // Who knows?

Programmieren ist keine schwarze Magie. Variablen werden nicht plötzlich zu Null. Wenn Sie eine Variable wissen , ist nicht Null, und Sie wissen , dass es nicht geändert wird , dann kann nicht überprüfen Sie es.

Wenn Sie es überprüfen, werden einige Programmierer in der Zukunft (möglicherweise Sie) viel Zeit damit verbringen, herauszufinden, warum diese Überprüfung vorhanden ist. Der Scheck muss doch aus einem Grund da sein, also was übersehen Sie?

MSalters
quelle
3
Der @NonnullVertrag sieht vor, dass Aufrufer nicht nullan den Konstruktor übergeben werden dürfen, und FindBugs verwendet eine statische Analyse, um Aufrufe zu finden, die null--spezifisch Aufrufe zulassen , die Werte übergeben, die @Nonnullselbst nicht markiert sind. Es steht dem Anrufer jedoch frei null, die Warnung von FindBugs zu ignorieren.
David Harkness
Programmierung ist im Idealfall keine schwarze Magie. Leider gibt es viele Vorbehalte und Überraschungen, insbesondere bei der Arbeit mit einigen der Nebenläufigkeitscodes
Tim Harper