Ich habe einen Code, der wegen NullPointerException fehlschlägt. Für das Objekt wird eine Methode aufgerufen, bei der das Objekt nicht vorhanden ist.
Dies veranlasste mich jedoch, über den besten Weg nachzudenken, um dies zu beheben. Codiere ich immer defensiv für Nullen, damit ich zukunftssicheren Code für Nullzeigerausnahmen erhalte, oder behebe ich die Ursache für die Null, damit sie nicht nachgeschaltet auftritt.
Was sind deine Gedanken?
Antworten:
Wenn null ein sinnvoller Eingabeparameter für Ihre Methode ist, korrigieren Sie die Methode. Wenn nicht, beheben Sie den Anrufer. "Vernünftig" ist ein flexibler Begriff, daher schlage ich den folgenden Test vor: Wie soll die Methode eine Null-Eingabe behandeln? Wenn Sie mehr als eine mögliche Antwort finden, ist Null keine sinnvolle Eingabe.
quelle
Precondition.checkNotNull(...)
. Siehe stackoverflow.com/questions/3022319/…IllegalArgumentException
wenn null angegeben wird. Dies signalisiert den Aufrufern der Methode, dass sich der Fehler in ihrem Code befindet (und nicht in der Methode selbst).Verwenden Sie nicht null, sondern optional
Wie Sie bereits betont haben, besteht eines der größten Probleme
null
in Java darin, dass es überall oder zumindest für alle Referenztypen verwendet werden kann.Es ist unmöglich zu sagen, dass das sein könnte
null
und was nicht sein könnte.Java 8 bietet eine viel bessere Muster:
Optional
.Und ein Beispiel von Oracle:
Wenn jeder dieser Werte einen erfolgreichen Wert zurückgibt oder nicht, können Sie die APIs in
Optional
s ändern :Durch die explizite Codierung von Optionalität im Typ werden Ihre Schnittstellen viel besser und Ihr Code wird sauberer.
Wenn Sie nicht Java 8 verwenden, können Sie
com.google.common.base.Optional
in Google Guava nachsehen .Eine gute Erklärung vom Guava-Team: https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained
Eine allgemeinere Erklärung der Nachteile gegen Null mit Beispielen aus mehreren Sprachen: https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/
@Nonnull, @Nullable
Java 8 fügt diese Annotation hinzu, um Tools zur Codeüberprüfung wie IDEs beim Erkennen von Problemen zu unterstützen. Sie sind in ihrer Wirksamkeit ziemlich begrenzt.
Prüfen Sie, wann es Sinn macht
Schreiben Sie nicht 50% Ihres Codes und überprüfen Sie null, insbesondere wenn es nichts Sinnvolles gibt, das Ihr Code mit einem
null
Wert tun kann.Auf der anderen Seite sollten Sie
null
sicherstellen, dass Sie etwas verwenden , wenn es verwendet werden könnte und etwas bedeutet.Letztendlich kann man
null
Java natürlich nicht entfernen . Ich empfehle nachdrücklich, dieOptional
Abstraktion zu ersetzen, wann immer dies möglich ist, und zu überprüfennull
, ob Sie in anderen Fällen etwas Vernünftiges tun können.quelle
NullPointerException
? ANullPointerException
kann buchstäblich jedes Mal auftreten, wenn Sie eine Instanzmethode in Java aufrufen. Sie würdenthrows NullPointerException
in fast jeder einzelnen Methode jemals haben.Es gibt mehrere Möglichkeiten, damit umzugehen. Das Peppen Ihres Codes
if (obj != null) {}
ist nicht ideal, es ist chaotisch, es verursacht beim späteren Lesen des Codes während des Wartungszyklus Geräusche und ist fehleranfällig, da es leicht zu vergessen ist, diese Boiler- Plattenumhüllung vorzunehmen .Es hängt davon ab, ob der Code weiterhin im Hintergrund ausgeführt werden soll oder fehlschlägt. Ist das
null
ein Fehler oder eine erwartete Bedingung.Was ist null?
In jeder Definition und jedem Fall steht Null für den absoluten Mangel an Daten. Nullen in Datenbanken stehen für das Fehlen eines Werts für diese Spalte. Eine Null
String
ist nicht dasselbe wie eine leereString
, eine Nullint
ist theoretisch nicht dasselbe wie NULL. In der Praxis "kommt es darauf an". EmptyString
kann eine guteNull Object
Implementierung für die String-Klasse darstellen, daInteger
dies von der Geschäftslogik abhängt.Alternativen sind:
Das
Null Object
Muster. Erstellen Sie eine Instanz Ihres Objekts, die dennull
Status darstellt, und initialisieren Sie alle Verweise auf diesen Typ mit einem Verweis auf dieNull
Implementierung. Dies ist nützlich für einfache Werttyp - Objekte , die nicht viel von Verweisen auf andere Objekte, die auch sein könnte ,null
sein und wird voraussichtlichnull
als einen gültigen Zustand.Verwenden Sie aspektorientierte Werkzeuge, um Methoden mit einem
Null Checker
Aspekt zu weben , der verhindert, dass die Parameter null sind. Dies gilt für Fälle, in denennull
ein Fehler vorliegt.Verwenden Sie
assert()
nicht viel besser als die,if (obj != null){}
aber weniger Lärm.Verwenden Sie ein Vertragsdurchsetzungsprogramm wie " Verträge für Java" . Gleicher Anwendungsfall wie AspectJ, jedoch neuer und verwendet Anmerkungen anstelle externer Konfigurationsdateien. Das Beste aus beiden Arbeiten von Aspects and Asserts.
1 ist die ideale Lösung, wenn bekannt ist, dass eingehende Daten
null
durch einen Standardwert ersetzt werden müssen, damit sich vorgelagerte Verbraucher nicht mit dem gesamten Code für die Überprüfung des Nullwerts auseinandersetzen müssen. Das Abgleichen mit bekannten Standardwerten ist ebenfalls aussagekräftiger.2, 3 und 4 sind nur praktische Alternativen, um Ausnahmegeneratoren durch
NullPointerException
etwas Informativeres zu ersetzen , was immer eine Verbesserung darstellt.Schlussendlich
null
in Java ist fast immer ein logischer Fehler. Sie sollten sich immer bemühen, die Grundursache zu beseitigenNullPointerExceptions
. Sie sollten sich bemühen,null
Bedingungen nicht als Geschäftslogik zu verwenden.if (x == null) { i = someDefault; }
Nehmen Sie einfach die erste Zuweisung zu dieser Standardobjektinstanz vor.quelle
null
unerwartet ist, dann ist es ein echter Fehler, dann sollte alles zum Stillstand kommen.null == null
(auch in PHP), aber in Datenbanken,null != null
weil es in Datenbanken einen unbekannten Wert darstellt und nicht "nichts". Zwei Unbekannte sind nicht unbedingt gleich, während zwei Nichts gleich sind.Das Hinzufügen von Nullprüfungen kann das Testen problematisch machen. Sehen Sie sich diesen tollen Vortrag an ...
Schauen Sie sich den Vortrag zu Google Tech Talks an: "Die Clean Code Talks - Suchen Sie nicht nach Dingen!" Er spricht ungefähr in Minute 24 darüber
http://www.youtube.com/watch?v=RlfLCWKxHJ0&list=PL693EFD059797C21E
Bei der paranoiden Programmierung werden überall Nullprüfungen hinzugefügt. Auf den ersten Blick scheint es eine gute Idee zu sein, aber aus der Sicht des Testens ist es schwierig, mit dem Null-Check-Typ-Test umzugehen.
Auch, wenn Sie eine Voraussetzung für die Existenz eines Objekts wie erstellen
Es verhindert, dass Sie House erstellen, da Sie eine Ausnahme auslösen. Angenommen, Ihre Testfälle erstellen Scheinobjekte zum Testen von etwas anderem als "Tür". Sie können dies nicht tun, da "Tür" erforderlich ist
Diejenigen, die unter der Hölle der Scheinschöpfung gelitten haben, sind sich dieser Art von Ärger wohl bewusst.
Zusammenfassend sollte Ihre Testsuite robust genug sein, um auf Türen, Häuser, Dächer oder was auch immer zu testen, ohne paranoid zu sein. Seroiusly, wie schwierig ist es, einen Null-Check-Test für bestimmte Objekte in Ihrem Test hinzuzufügen :)
Sie sollten immer Anwendungen bevorzugen, die funktionieren, weil Sie mehrere Tests haben, die BEWÄHREN, dass es funktioniert, und nicht HOPFEN, weil Sie überall eine ganze Reihe von vorbedingten Nullprüfungen haben
quelle
tl; dr - Es ist GUT, nach unerwarteten
null
s zu suchen, aber SCHLECHT, wenn eine Anwendung versucht, sie zu verbessern.Einzelheiten
Offensichtlich gibt es Situationen, in denen
null
es eine gültige Eingabe oder Ausgabe für eine Methode gibt, und andere, in denen dies nicht der Fall ist.Regel 1:
Regel 2:
Angesichts einer klaren Spezifikation des "Vertrags" einer Methode gegenüber dem "Vertrag"
null
ist es ein Programmierfehler, ein zu übergeben oder zurückzugeben,null
wo Sie nicht sollten.Regel 3:
Wenn eine Methode eine erkennt ,
null
die nicht da sein sollte, sollte es nicht versuchen , das Problem zu beheben , indem sie in etwas anderes verwandeln. Das verbirgt das Problem nur vor dem Programmierer. Stattdessen sollte NPE zugelassen und ein Fehler verursacht werden, damit der Programmierer die Ursache ermitteln und beheben kann. Hoffentlich wird der Fehler beim Testen bemerkt. Wenn nicht, sagt das etwas über Ihre Testmethode aus.Regel 4:
Wenn Ihr Code Fehler enthält, die zu vielen NPEs führen, kann es am schwierigsten sein, herauszufinden, woher die
null
Werte stammen. Eine Möglichkeit , die Diagnose zu erleichtern ist der Code zu schreiben , so dass dienull
so schnell wie möglich erkannt werden. Oft können Sie dies in Verbindung mit anderen Überprüfungen tun. z.B(Natürlich gibt es Fälle , in denen Regeln 3 und 4 sollte mit der Realität temperiert werden. Zum Beispiel (Regel 3), einige Arten von Anwendungen müssen nach dem Erkennen wahrscheinlich Programmierfehler weiterhin versuchen. Und (Regel 4) zu viel Kontrolle für schlechte Parameter haben kann eine Leistungsbeeinträchtigung.)
quelle
Ich würde empfehlen, die Methode defensiv zu machen. Zum Beispiel:
Sollte mehr entlang den Linien dieses:
Ich weiß, dies absolut trivial ist, aber wenn der Aufrufer ein Objekt erwartet, dass sie ein Standard-Objekt geben, die nicht Ursache eine Null herumgereicht werden.
quelle
new String()
.null
s ist die denkbar schlechteste Option, schlimmer als ein NPE zu werfen.Die folgenden allgemeinen Regeln über null haben mir sehr geholfen, so weit:
Wenn die Daten von außerhalb Ihrer Kontrolle stammen, suchen Sie systematisch nach Nullen und handeln Sie entsprechend. Dies bedeutet, dass entweder eine Ausnahme ausgelöst wird, die für die Funktion sinnvoll ist (aktiviert oder deaktiviert, stellen Sie nur sicher, dass der Name der Ausnahme genau angibt, was gerade passiert.). Aber VERLIEREN SIE NIEMALS einen Wert in Ihrem System, der möglicherweise Überraschungen birgt.
Wenn Null im Bereich der für Ihr Datenmodell geeigneten Werte liegt, müssen Sie entsprechend vorgehen.
Versuchen Sie bei der Rückgabe von Werten, möglichst keine Nullen zurückzugeben. Bevorzugen Sie immer leere Listen, leere Zeichenfolgen und Null-Objektmuster. Behalten Sie Nullen als zurückgegebene Werte bei, wenn dies die bestmögliche Darstellung von Daten für einen bestimmten Anwendungsfall ist.
Das wohl wichtigste von allen ... Tests, Tests und nochmal testen. Wenn Sie Ihren Code testen, testen Sie ihn nicht als Kodierer. Testen Sie ihn als Domina eines NS-Psychopathen und versuchen Sie sich alle möglichen Methoden vorzustellen, um den Code zu quälen.
Dies ist paranoid, was Nullen betrifft, die häufig zu Fassaden und Proxies führen, die Systeme mit der Außenwelt verbinden, und streng kontrollierte Werte im Inneren mit reichlich Redundanz. Die Außenwelt bedeutet hier so ziemlich alles, was ich nicht selbst codiert habe. Es macht einen Kosten Laufzeit tragen aber bisher habe ich selten dies hatte zur Optimierung von „null sichere Abschnitte“ des Codes zu schaffen. Ich muss jedoch sagen, dass ich hauptsächlich Systeme für das Gesundheitswesen erstelle, und das letzte, was ich möchte, ist, dass das Schnittstellensubsystem, das Ihre Jodallergien auf den CT-Scanner überträgt, aufgrund eines unerwarteten Nullzeigers abstürzt, weil jemand anderes in einem anderen System nie realisiert hat, dass Namen dies könnten Enthält Apostrophe oder Zeichen wie 但 但 耒耨
sowieso .... meine 2 Cent
quelle
Ich würde vorschlagen, Option / Some / None-Muster aus funktionalen Sprachen zu verwenden. Ich bin kein Java-Spezialist, aber ich benutze intensiv meine eigene Implementierung dieses Musters in meinem C # -Projekt, und ich bin sicher, könnte es in Java-Welt überführt werden.
Die Idee hinter diesem Muster ist: Wenn es logisch ist, eine Situation zu haben, in der die Möglichkeit des Fehlens eines Werts besteht (zum Beispiel beim Abrufen von der Datenbank über die ID), geben Sie ein Objekt vom Typ Option [T] an, wobei T ein möglicher Wert ist . I Fall von absense eines Wertes Objekt der Klasse Keine [T] zurückgegeben, im Falle, wenn Existenz des Wertes - Ziel einiger [T] zurückgegeben, die den Wert enthält.
In diesem Fall Sie müssen die Möglichkeit Wert Abwesenheit handhaben , und wenn Sie Code - Review tun könnten Sie leicht placec unsachgemäßer Handhabung gefunden. Informationen zur Implementierung von C # finden Sie in meinem Bitbucket-Repository unter https://bitbucket.org/mikegirkin/optionsomenone
Wenn Sie einen Nullwert zurückgeben und dieser logisch dem Fehler entspricht (z. B. dass keine Datei vorhanden ist oder keine Verbindung hergestellt werden konnte), sollten Sie eine Ausnahme auslösen oder ein anderes Fehlerbehandlungsmuster verwenden. Die Idee dahinter, wieder, beenden Sie mit Lösung auf, wenn Sie müssen die Situation der Wert Abwesenheit handhaben , und einfach die Orte unsachgemäßer Handhabung im Code gefunden.
quelle
Nun, wenn eines der möglichen Ergebnisse Ihrer Methode ein Nullwert ist, sollten Sie dies defensiv codieren, aber wenn eine Methode einen Nicht-Nullwert zurückgeben soll, aber nicht, würde ich das mit Sicherheit beheben.
Wie immer kommt es auf den Fall an, wie bei den meisten Dingen im Leben :)
quelle
Die lang- Bibliotheken von Apache Commons bieten eine Möglichkeit, mit Nullwerten umzugehen
Mit der Methode defaultIfNull in der Klasse ObjectUtils können Sie einen Standardwert zurückgeben, wenn das übergebene Objekt null ist
quelle
Verwenden Sie den optionalen Typ nicht, es sei denn, er ist wirklich optional. Oft wird der Exit als Ausnahme besser behandelt, es sei denn, Sie haben wirklich null als Option erwartet und nicht, weil Sie regelmäßig fehlerhaften Code schreiben.
Das Problem ist nicht null als eine Art es seinen Nutzen hat, wie Google-Artikel weist darauf hin. Das Problem ist, dass NULL-Werte überprüft werden sollen und behandelt, oft können sie anmutig verlassen werden.
Es gibt eine Reihe von Nullfällen, die ungültige Bedingungen in Bereichen außerhalb des normalen Programmbetriebs darstellen (ungültige Benutzereingaben, Datenbankprobleme, Netzwerkfehler, fehlende Dateien, beschädigte Daten) wenn es nur ist, um es zu protokollieren.
Für die Ausnahmebehandlung sind in der JVM andere Betriebsprioritäten und -berechtigungen zulässig als für einen Typ wie Optional, der für die Ausnahmebedingung sinnvoll ist, einschließlich der frühen Unterstützung für das priorisierte verzögerte Laden des Handlers in den Speicher, da dies nicht der Fall ist brauchen sie hängen die ganze Zeit herum.
Sie müssen keine Null-Handler überall schreiben, nur dort, wo sie wahrscheinlich auftreten, wo Sie möglicherweise auf einen unzuverlässigen Datendienst zugreifen, und da die meisten dieser Handler in wenige allgemeine Muster unterteilt sind, die leicht abstrahiert werden können, brauchen Sie wirklich nur ein Handler Aufruf, außer in seltenen Fällen.
Ich schätze, meine Antwort wäre, es in eine überprüfte Ausnahme zu packen und damit umzugehen, oder den unzuverlässigen Code zu reparieren, wenn er in Ihren Zuständigkeitsbereich fällt.
quelle