Was ist der Sinn von Guava checkNotNull [duplicate]

Lesezeit: 8 Minuten

Benutzer-Avatar
Ar3s

Ich bin ziemlich neu bei Guava (seien wir ehrlich, ich bin nicht “ziemlich neu”, ich bin ein absoluter Neuling in diesem Thema) und so habe ich beschlossen, einige Dokumentationen durchzugehen und war ziemlich erstaunt, als ich dies las:

com.google.common.base.Preconditions.checkNotNull(...)

Ich verstehe den Sinn dieser Methode nicht. Dies bedeutet, dass anstatt zu tun:

myObject.getAnything();

(was dazu führen kann, dass a NullPointerException wenn meinObjekt null ist)

sollte ich verwenden

checkNotNull(myObject).getAnything();

die Wille Werfen Sie einen NullPointerException wenn myObject ist null und kehrt zurück myObject wenn es nicht null ist.

Ich bin verwirrt und das ist vielleicht die dümmste Frage aller Zeiten, aber …

Was ist der Sinn davon? Diese beiden Zeilen machen genau dasselbe wie für Ergebnisse in allen Situationen, die mir einfallen.

Ich glaube nicht einmal, dass letzteres besser lesbar ist.

Also muss mir etwas fehlen. Was ist es?

  • Ich glaube nicht wirklich an die Idee, checkNotNull an jeder Stelle hinzuzufügen. IMHO wäre es besser, wenn Sie Ihre Eingabe explizit überprüfen, anstatt sich zu sehr auf den syntaktischen Zucker zu verlassen, der hilft, Ihren Code zu verschleiern. Fail fast ist in Ordnung, aber checkNotNull gibt einfach keine weiteren Informationen zur Fehlerbehebung –> Sie können einfach Ihre eigene Ausnahme für ein falsches Eingabeformat machen und eine nette Nachricht einfügen, die die spezifische Situation erklärt

    – Hoàng Long

    21. Dezember 2015 um 6:53 Uhr

  • Ich stimme vollkommen zu, dass das lächerlich ist. Auf null zu prüfen und dann selbst einen NPE zu werfen, ist meiner bescheidenen Meinung nach völlig verrückt. Lösen Sie mindestens eine ValidationException oder IllegalArgumentException aus.

    – Laurentius

    29. August 2016 um 16:33 Uhr

  • Erwägen Sie die Bereitstellung einer besseren Diagnose mit checkNotNull(reference, errorMessageTemplate, errorMessageArgs): guava.dev/releases/23.0/api/docs/com/google/common/base/…

    – Wadzim

    16. Juni 2020 um 15:33 Uhr

Benutzer-Avatar
yschavit

Die Idee ist, schnell zu scheitern. Betrachten Sie zum Beispiel diese dumme Klasse:

public class Foo {
    private final String s;

    public Foo(String s) {
        this.s = s;
    }

    public int getStringLength() {
        return s.length();
    }
}

Angenommen, Sie möchten keine Nullwerte für zulassen s. (oder aber getStringLength wird ein NPE werfen). Mit der Klasse, wie sie ist, bis Sie das verstanden haben null, es ist zu spät – es ist sehr schwer herauszufinden, wer es dort hingelegt hat. Der Schuldige könnte durchaus in einer ganz anderen Klasse sein, und das Foo Instanz hätte vor langer Zeit gebaut werden können. Jetzt müssen Sie Ihre Codebasis durchkämmen, um herauszufinden, wer möglicherweise einen eingefügt haben könnte null Wert dort.

Stellen Sie sich stattdessen diesen Konstruktor vor:

public Foo(String s) {
    this.s = checkNotNull(s);
}

Nun, wenn jemand ein setzt null da drin wirst du es erfahren sofort — und der Stack-Trace zeigt Ihnen genau den Aufruf, der schief gelaufen ist.


Ein anderer Fall, in dem dies nützlich sein kann, ist, wenn Sie die Argumente überprüfen möchten, bevor Sie Maßnahmen ergreifen, die den Status ändern können. Betrachten Sie zum Beispiel diese Klasse, die den Durchschnitt aller erhaltenen Zeichenfolgenlängen berechnet:

public class StringLengthAverager {
    private int stringsSeen;
    private int totalLengthSeen;

    public void accept(String s) {
        stringsSeen++;
        totalLengthSeen += s.length();
    }

    public double getAverageLength() {
        return ((double)totalLengthSeen) / stringsSeen;
    }
}

Berufung accept(null) wird dazu führen, dass ein NPE geworfen wird – aber nicht vorher stringsSeen wurde erhöht. Das ist vielleicht nicht das, was Sie wollen; Als Benutzer der Klasse kann ich erwarten, dass, wenn sie keine Nullen akzeptiert, ihr Zustand unverändert bleiben sollte, wenn Sie eine Null übergeben (mit anderen Worten: der Aufruf sollte fehlschlagen, aber das Objekt nicht ungültig machen). Offensichtlich könnten Sie es in diesem Beispiel auch beheben, indem Sie es bekommen s.length() vor dem Inkrementieren stringsSeenaber Sie können sehen, dass es für eine längere und kompliziertere Methode nützlich sein kann, zuerst zu überprüfen, ob alle Ihre Argumente gültig sind, und erst dann den Status zu ändern:

    public void accept(String s) {
        checkNotNull(s); // that is, s != null is a precondition of the method

        stringsSeen++;
        totalLengthSeen += s.length();
    }

  • Sollte es nicht mehr sein this.s=Preconditions.checkNotNull(s);

    – Ar3s

    3. Oktober 2014 um 18:32 Uhr

  • Aber ja, an die Aufbewahrungsbox habe ich nicht gedacht.

    – Ar3s

    3. Oktober 2014 um 18:33 Uhr

  • Das typische Muster ist this.s = checkNotNull(s); mit einem statischen Import.

    – ColinD

    3. Oktober 2014 um 18:33 Uhr

  • Ich persönlich denke, dass diese Art der Fehlermeldung vermieden werden sollte. Was auch immer Sie tun, eine NullPointerException hat buchstäblich wenig bis gar keine Bedeutung. Ich bin entschieden dagegen, null in JEDER Funktion zu übergeben/zurückzugeben (es sei denn, Sie arbeiten mit einer Legacy-API), daher sollte jeder Versuch, dies zu tun, eine WrongApiUsage-Ausnahme ins Gesicht schlagen.

    – Hoàng Long

    21. Dezember 2015 um 6:41 Uhr


  • @HoàngLong Das wünsche ich mir auch checkNotNull würde eine IllegalArgumentException anstelle von NPE auslösen. Für mich bedeutet ein NPE, dass jemand versucht hat, einen Nullzeiger zu dereferenzieren – nicht, dass jemand die Tatsache bemerkt hat, dass er null war, bevor er versucht hat, ihn zu dereferenzieren. Aber abgesehen davon denke ich auch, dass “IllegalArgumentException: foo was null” in praktischer Hinsicht nicht hilfreicher ist als “NullPointerException: foo”. Also, während ich mir irgendwie wünschte, die Leute von Guava hätten IllegalArgumentException ausgewählt, die Bequemlichkeit und Standardisierung von checkNotNull Überschreiben Sie diesen Nit, zumindest für mich.

    – yshavit

    2. März 2016 um 15:10 Uhr


Benutzer-Avatar
maaartinus

myObject.getAnything(); (was eine NullPointerException verursachen kann, wenn myObject null ist)

Nein, es Wille Werfen Sie NPE wann immer myObject == null. In Java gibt es keine Möglichkeit, eine Methode mit aufzurufen null Empfänger (eine theoretische Ausnahme sind statische Methoden, aber sie können und sollten immer ohne Objekt aufgerufen werden).


sollte ich verwenden checkNotNull(myObject).getAnything();

Nein solltest du nicht. Das wäre ziemlich überflüssig (Aktualisieren).

Du solltest benutzen checkNotNull um zu scheitern schnell. Ohne sie können Sie eine illegale passieren null zu einer anderen Methode, die es weiterleitet, und so weiter und so weiter, wo es schließlich fehlschlägt. Dann kann es schon etwas Glück brauchen, um herauszufinden, dass eigentlich die allererste Methode hätte ablehnen müssen null.


Die Antwort von yshavit erwähnt einen wichtigen Punkt: Das Übergeben eines illegalen Werts ist schlecht, aber das Speichern und spätere Übergeben ist noch schlimmer.

Aktualisieren

Eigentlich,

 checkNotNull(myObject).getAnything()

macht auch Sinn, da Sie Ihre Absicht klar zum Ausdruck bringen, keine Nullen zu akzeptieren. Ohne sie könnte jemand denken, dass Sie den Scheck vergessen haben, und ihn in so etwas umwandeln

 myObject != null ? myObject.getAnything() : somethingElse

OTOH, ich glaube nicht, dass der Scheck die Ausführlichkeit wert ist. In einem bessere Sprachewürde das Typsystem die Nullfähigkeit berücksichtigen und uns etwas semantischen Zucker wie geben

 myObject!!.getAnything()                    // checkNotNull
 myObject?.getAnything()                     // safe call else null
 myObject?.getAnything() ?: somethingElse    // safe call else somethingElse

für nullable myObjectwährend die standardmäßige Punktsyntax nur zulässig wäre, wenn myObject ist bekanntermaßen nicht null.

  • Das ist also so, als würde man zu Beginn einer Methode überprüfen, ob eine Vorbedingung für die Methode gültig ist?

    – Juru

    3. Oktober 2014 um 18:15 Uhr

  • Exakt. Die sofortige Überprüfung auf illegale Argumente stellt sicher, dass Sie sie später nicht finden müssen. Außerdem sieht jeder, der sich die Methode ansieht, was verboten ist (klar, sollte dokumentiert werden…).

    – maaartinus

    3. Oktober 2014 um 18:18 Uhr

  • @Juru: Ja, deshalb ist es in der Preconditions Klasse!

    – ColinD

    3. Oktober 2014 um 18:34 Uhr

Ich habe diesen ganzen Thread vor ein paar Minuten gelesen. Trotzdem war ich verwirrt, warum sollten wir verwenden checkNotNull. Dann schauen Sie sich das Precondition-Klassendokument von Guava an und ich habe bekommen, was ich erwartet habe. Übermäßiger Gebrauch von checkNotNull wird definitiv die Leistung verschlechtern.

Mein Gedanke ist checkNotNull Methode lohnt sich erforderlich für Datenvalidierung, die direkt vom Benutzer kommt oder ganz am Ende der API zur Benutzerinteraktion. Es sollte nicht in allen Methoden der internen API verwendet werden, da Sie mit ihm Ausnahmen nicht stoppen können, sondern Ihre interne API korrigieren, um Ausnahmen zu vermeiden.

Laut DOC: Verknüpfung

Verwendung von checkNotNull:

public static double sqrt(double value) {
     Preconditions.checkArgument(value >= 0.0, "negative value: %s", value);
     // calculate the square root
}

Warnung vor Leistung

Das Ziel dieser Klasse ist es, die Lesbarkeit des Codes zu verbessern, aber unter bestimmten Umständen kann dies zu erheblichen Leistungseinbußen führen. Denken Sie daran, dass die Parameterwerte für die Nachrichtenkonstruktion alle eifrig berechnet werden müssen und dass Autoboxing und die Erstellung von Varargs-Arrays ebenfalls vorkommen können, selbst wenn die Vorbedingungsprüfung dann erfolgreich ist (was in der Produktion fast immer der Fall sein sollte). Unter bestimmten Umständen können sich diese verschwendeten CPU-Zyklen und Zuweisungen zu einem echten Problem summieren. Performance-sensitive Vorbedingungsprüfungen können immer in die übliche Form umgewandelt werden:

if (value < 0.0) {
     throw new IllegalArgumentException("negative value: " + value);
}

  • Geben Sie -1, sorry: Ich empfehle nicht, dies für die Validierung von Benutzerdaten zu verwenden, da Sie dem Benutzer eine benutzerfreundlichere, nicht technische Fehlermeldung geben möchten. Auch Laufzeitausnahmen sind nicht vorgesehen, falls die unberechenbare Situation zu erwarten ist. Es ist zu erwarten, dass ein Benutzer hin und wieder einen Fehler macht. Ich würde vorschlagen, Methodenargumente in öffentlichen Methoden zu überprüfen, aber nicht in privaten Methoden. Früheres Abfangen von Programmierfehlern ist mehr wert als vorzeitige Optimierung. Ersetzen Sie die Vorbedingungsprüfung nur, wenn Sie feststellen, dass es sich tatsächlich um ein Leistungsproblem handelt.

    – Henno Vermeulen

    31. August 2018 um 14:53 Uhr


  • @HennoVermeulen Wie Sie sagten “Überprüfen von Methodenargumenten in öffentlichen Methoden”, sagte ich auch: “Es sollte nicht in jeder Methode der internen API verwendet werden”. Vielen Dank

    – iamcrypticcoder

    31. August 2018 um 16:24 Uhr


  • Upvoted für das Heads-up zur Leistung, aber wie andere gesagt haben, kein großartiger Ansatz für die Benutzervalidierung!

    – Tullochgorum

    8. November 2019 um 17:13 Uhr

1178940cookie-checkWas ist der Sinn von Guava checkNotNull [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy