Ich bin ziemlich neu in Guava (seien wir ehrlich, ich bin nicht "ziemlich neu", ich bin ein absoluter Neuling in diesem Bereich) und habe mich daher entschlossen, einige Dokumentationen durchzugehen und war beim Lesen ziemlich erstaunt:
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 myObject null ist)
Ich sollte verwenden
checkNotNull(myObject).getAnything();
was wird ein Wurf , NullPointerException
wenn myObject
null und Rückkehr ist , myObject
wenn es nicht null ist.
Ich bin verwirrt und dies könnte die dümmste Frage sein, aber ...
Was ist der Sinn davon? Diese beiden Zeilen machen genau das Gleiche wie für die Ergebnisse in allen Situationen, die mir einfallen.
Ich denke nicht einmal, dass Letzteres besser lesbar ist.
Also muss mir etwas fehlen. Was ist es?
quelle
checkNotNull(reference, errorMessageTemplate, errorMessageArgs)
: guava.dev/releases/23.0/api/docs/com/google/common/base/…Antworten:
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
. (odergetStringLength
wirft eine NPE). Wenn die Klasse so ist wie sie ist,null
ist es zu spät - es ist sehr schwer herauszufinden, wer sie dort abgelegt hat. Der Täter könnte durchaus in einer völlig anderen Klasse sein, und dieseFoo
Instanz könnte vor langer Zeit konstruiert worden sein. Jetzt müssen Sie Ihre Codebasis durchkämmen, um herauszufinden, wer dort möglicherweise einennull
Wert hätte setzen können.Stellen Sie sich stattdessen diesen Konstruktor vor:
public Foo(String s) { this.s = checkNotNull(s); }
Wenn jemand dort einen Eintrag einfügt
null
, werden Sie es sofort herausfinden - und der Stack-Trace zeigt Sie genau auf den fehlgeschlagenen Aufruf.Ein anderes Mal kann dies nützlich sein, wenn Sie die Argumente überprüfen möchten, bevor Sie Aktionen ausführen, mit denen der Status geändert werden kann. Betrachten Sie beispielsweise 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; } }
Beim Aufrufen
accept(null)
wird eine NPE ausgelöst - jedoch nicht zuvorstringsSeen
. Dies ist möglicherweise nicht das, was Sie wollen. Als Benutzer der Klasse kann ich erwarten, dass der Status unverändert bleibt, wenn keine Nullen akzeptiert werden, wenn Sie eine Null übergeben (mit anderen Worten: Der Aufruf sollte fehlschlagen, das Objekt jedoch nicht ungültig werden). In diesem Beispiel können Sie das Problem natürlich auch beheben, indem Sie ess.length()
vor dem Inkrementieren abrufenstringsSeen
. Sie können jedoch sehen, dass es für eine längere und aufwändigere Methode hilfreich sein kann, zunächst 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(); }
quelle
this.s = checkNotNull(s);
ein statischer Import.checkNotNull
würde eine IllegalArgumentException anstelle von NPE auslösen. Für mich bedeutet eine NPE, dass jemand versucht hat, einen Nullzeiger zu dereferenzieren - nicht, dass jemand die Tatsache erkannt hat, dass er null war, bevor er versucht hat, ihn zu dereferenzieren. Vor diesem Hintergrund denke ich auch, dass "IllegalArgumentException: foo was null" in keiner praktischen Hinsicht hilfreicher ist als "NullPointerException: foo". Also, während ich mir irgendwie wünsche, dass die Guaven-Leute IllegalArgumentException ausgewählt haben, ist die Bequemlichkeit und Standardisierung der AußerkraftsetzungcheckNotNull
zumindest für mich nicht der Fall .Nein ... es wird immer NPE werfen
myObject == null
. In Java gibt es keine Möglichkeit, eine Methode mitnull
Empfänger aufzurufen (eine theoretische Ausnahme sind statische Methoden, aber sie können und sollten immer ohne Objekt aufgerufen werden).Nein, solltest du nicht. Dies wäre eher redundant ( Update ).
Sie sollten verwenden,
checkNotNull
um schnell zu versagen . Ohne sie können Sie ein Illegalesnull
an eine andere Methode übergeben, die es weiterleitet, und so weiter und so fort, wo es schließlich fehlschlägt. Dann können Sie etwas Glück brauchen, um herauszufinden, dass eigentlich die allererste Methode abgelehnt haben solltenull
.Die Antwort von yshavit erwähnt einen wichtigen Punkt: Es ist schlecht, einen illegalen Wert zu übergeben, aber es ist noch schlimmer, ihn zu speichern und später weiterzugeben.
Aktualisieren
Tatsächlich,
Dies ist auch sinnvoll, da Sie klar Ihre Absicht 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 denke nicht, dass der Scheck die Ausführlichkeit wert ist. In einer besseren Sprache würde das Typsystem die Nullbarkeit berücksichtigen und uns etwas semantischen Zucker geben
myObject!!.getAnything() // checkNotNull myObject?.getAnything() // safe call else null myObject?.getAnything() ?: somethingElse // safe call else somethingElse
für nullable
myObject
, während die Standard-Punktsyntax nur zulässig ist, wennmyObject
bekannt ist, dass sie nicht null ist.quelle
Preconditions
Klasse!Ich habe diesen ganzen Thread vor ein paar Minuten gelesen. Trotzdem war ich verwirrt, warum wir verwenden sollten
checkNotNull
. Dann schauen Sie sich das Precondition Class Doc von Guava an und ich habe bekommen, was ich erwartet hatte. Übermäßiger GebrauchcheckNotNull
beeinträchtigt die Leistung definitiv.Meiner Meinung nach ist eine
checkNotNull
Methode für die Datenvalidierung erforderlich, die vom Benutzer direkt oder von der End-API zur Benutzerinteraktion erfolgt. Es sollte nicht in allen Methoden der internen API verwendet werden, da Sie mit dieser Ausnahme keine Ausnahme stoppen können, sondern Ihre interne API korrigieren müssen, um Ausnahmen zu vermeiden.Laut DOC: Link
public static double sqrt(double value) { Preconditions.checkArgument(value >= 0.0, "negative value: %s", value); // calculate the square root }
if (value < 0.0) { throw new IllegalArgumentException("negative value: " + value); }
quelle