Null-check chain vs Fang NullPointerException
Einen web service gibt eine riesige XML-und ich brauche Zugriff auf tief verschachtelte it-Bereichen. Zum Beispiel:
return wsObject.getFoo().getBar().getBaz().getInt()
Das problem ist, dass getFoo()
, getBar()
, getBaz()
können alle zurück null
.
Jedoch, wenn ich die Option für null
in allen Fällen, der code wird sehr ausführlich und schwer zu Lesen. Außerdem, ich kann miss die Prüfungen für einige der Felder.
if (wsObject.getFoo() == null) return -1;
if (wsObject.getFoo().getBar() == null) return -1;
//maybe also do something with wsObject.getFoo().getBar()
if (wsObject.getFoo().getBar().getBaz() == null) return -1;
return wsObject.getFoo().getBar().getBaz().getInt();
Ist es akzeptabel, zu schreiben,
try {
return wsObject.getFoo().getBar().getBaz().getInt();
} catch (NullPointerException ignored) {
return -1;
}
oder wäre das als ein antipattern?
- Ich würde nicht dagegen die
null
überprüft, dass viel, dawsObject.getFoo().getBar().getBaz().getInt()
ist bereits ein code smell. Lesen Sie, was die "Law of Demeter" ist und lieber überarbeiten Sie Ihren code entsprechend. Dann das problem mit dernull
Kontrollen werden so gut gegangen. Und denken über die VerwendungOptional
. - Was ist mit XPath und verlassen Sie es, um Ihre Bewertung?
- Dieser code wird wohl erzeugt durch
wsdl2java
ist, hat kein Respekt für das Gesetz von Demeter.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Fangen
NullPointerException
ist ein wirklich problematisch, was zu tun da können Sie passieren fast überall. Es ist sehr leicht zu bekommen, die man von einem bug, fängt es an durch Unfall und weitermachen, als wenn alles normal ist, wodurch ein echtes problem. Es ist so schwierig zu behandeln, so ist es am besten zu vermeiden. (Denken Sie zum Beispiel über auto-unboxing eines null -Integer
.)Ich empfehlen, dass Sie die
Optional
Klasse statt. Dies ist oft der beste Ansatz, wenn Sie wollen, um die Arbeit mit Werten, die entweder vorhanden oder nicht vorhanden.Verwenden, die Sie schreiben, könnte dein code wie folgt:
Warum optional?
Mit
Optional
s stattnull
für Werte, die möglicherweise fehlen, macht diese Tatsache sehr klar und sichtbar für die Leser, und das Typ-system wird sicherstellen, dass Sie nicht versehentlich vergessen.Erhalten Sie auch Zugang zu Methoden für die Arbeit mit diesen Werten mehr bequem, wie
map
undorElse
.Ist die Abwesenheit gültig ist oder Fehler?
Aber auch darüber nachdenken, ob es ein gültiges Ergebnis für den fortgeschrittene Methoden null zurück, oder wenn, dass ist ein Zeichen für einen Fehler. Wenn es ist immer ein Fehler, dann ist es wohl besser eine exception zu werfen, als die Rückgabe eines speziellen Wertes, oder für die fortgeschrittene Methoden selbst eine exception werfen.
Vielleicht mehr Optionen?
Wenn auf der anderen Seite fehlen die Werte aus dem temporären Methoden gültig sind, vielleicht können Sie wechseln, um
Optional
s für Sie auch?Dann können Sie Sie wie folgt:
Warum nicht optional?
Der einzige Grund, warum ich denken kann, für nicht mit
Optional
ist, wenn dies in einer wirklich performance-kritischen code-Abschnitt, und wenn die garbage collection overhead stellt sich heraus, ein problem zu sein. Dies ist, weil ein paarOptional
Objekte zugewiesen werden jedes mal, wenn der code ausgeführt wird, und die VM könnte nicht in der Lage sein, zu optimieren, entfernt. In diesem Fall Ihre original-wenn-tests besser sein könnte.Try
stattOptional
. Obwohl es keineTry
in der Java-API, es gibt viele libs bereitstellt, z.B. javaslang.io, github.com/bradleyscollins/try4j, functionaljava.org oder github.com/jasongoodwin/better-java-monadsFClass::getBar
etc wäre kürzer.static
Methode, die entstehen wird eine sehr geringe Strafe.Foo::getBar
sofort erzählt Sie, dass es ist eine Methode, die auf einemFoo
, die nicht ersichtlich ist, mit einem lambda. Aber mit der Dritten handgetBar
könnte sich um eine statische Methode oder mehr nehmen könnte, als ein argument, etc, diese Dinge sind klar mit einem lambda aber nicht mit einem meth-ref. Ich habe nicht in der Lage, eine starke Meinung darüber, welche Art am besten ist.Schlage ich vor, in Anbetracht
- Objekten.requireNonNull(T obj, String message)
. Sie bauen vielleicht Ketten mit einer ausführlichen Nachricht für jede Ausnahme, wieIch würde dir empfehlen nicht zu verwenden spezielle return-Werte, wie
-1
. Das ist kein Java-Stil. Java entworfen hat den Mechanismus von Ausnahmen zu vermeiden, die diese altmodische Art und Weise, die kam aus der C-Sprache.Werfen
NullPointerException
ist nicht die beste option zu. Sie könnten Ihre eigenen Ausnahme (die es überprüft garantieren, dass Sie bearbeitet werden, werden durch einen Benutzer oder deaktiviert zu verarbeiten, es in ein einfacherer Weg) oder verwenden Sie eine bestimmte Ausnahme aus dem XML-parser, die Sie verwenden.Objects.requireNonNull
schließlich wirftNullPointerException
. So dies nicht machen, wird die situation nicht anders alsreturn wsObject.getFoo().getBar().getBaz().getInt()
if
s als OP zeigteOptional
Klasse, oder vielleicht zurück eine null -Integer
Vorausgesetzt, die Klasse Struktur ist in der Tat außerhalb unserer Kontrolle, wie der Fall zu sein scheint, denke ich, fangen die NPE vorgeschlagen, in der Frage ist in der Tat eine vernünftige Lösung, es sei denn, die Leistung ist ein wichtiges Anliegen. Eine kleine Verbesserung könnte es sein, wickeln Sie das throw/catch-Logik, um Unordnung zu vermeiden:
Nun können Sie einfach tun:
Wie bereits betont, Tom in den Kommentar,
Folgende Anweisung nicht gehorcht der Gesetz von Demeter,
Was Sie wollen, ist
int
und Sie können es vonFoo
. Gesetz von Demeter sagt, reden nie um den fremden. Für Ihren Fall können Sie verstecken die eigentliche Implementierung unter der HaubeFoo
undBar
.Nun können Sie die create-Methode in
Foo
zu Holenint
ausBaz
. LetztlichFoo
habenBar
und inBar
können wir aufInt
ohne dassBaz
direkt zuFoo
. So, die null-Prüfungen sind wahrscheinlich aufgeteilt auf verschiedene Klassen und nur die erforderlichen Attribute werden geteilt zwischen den Klassen.null
überprüfen der eigenen sub-tags.Meine Antwort geht fast in die gleiche Zeile wie @janki, aber ich möchte zum ändern der code-snippet, das leicht wie folgt:
Können Sie ein null-check für
wsObject
wie gut, wenn es irgendeine chance, dass das Objekt null.Um die Lesbarkeit zu verbessern, können Sie verwenden mehrere Variablen, wie
Ihnen sagen, dass einige Methoden, die "möglicherweise zurück
null
" aber nicht sagen, in welchen Umständen Sie zurücknull
. Sie sagen, Sie fangen dieNullPointerException
aber Sie müssen nicht sagen, warum Sie es fangen. Dieser Mangel an Informationen schlägt vor, Sie nicht haben ein klares Verständnis von dem, was Ausnahmen sind und warum Sie besser sind als die alternative.Betrachten Sie eine Klasse Methode, die gemeint ist, um eine Aktion durchzuführen, aber die Methode kann nicht Garantie wird die Aktion durchzuführen, aufgrund von Umständen, die außerhalb seiner Kontrolle liegen (das ist in der Tat der Fall für alle - Methoden in Java). Wir nennen diese Methode und es gibt. Der code zum aufrufen dieser Methode muss wissen, ob es erfolgreich war. Wie kann es wissen? Wie kann es sein, strukturiert zu bewältigen mit den zwei Möglichkeiten, Erfolg oder Misserfolg?
Mit Ausnahmen kann man Methoden schreiben, die Erfolg als post-Zustand. Wenn die Methode zurückkehrt, war es erfolgreich. Wenn es eine Ausnahme wirft, es hatte versagt. Dies ist ein großer Gewinn für die übersichtlichkeit. Wir können code schreiben, der eindeutig auf Prozesse der normalen, Erfolg, Fall, und verschieben Sie alle die code für die Fehlerbehandlung in
catch
Klauseln. Oft stellt sich heraus, dass die details, wie oder warum eine Methode nicht erfolgreich war, sind nicht wichtig, der Anrufer, also das gleichecatch
- Klausel kann verwendet werden, für die Bearbeitung von verschiedenen Arten des Scheiterns. Und es passiert oft, dass ein Verfahren nicht zum abfangen von Ausnahmen an alle, sondern Sie können es Ihnen ermöglichen, zu verbreiten, zu seine Anrufer. Ausnahmen aufgrund von Programm-bugs werden in der letzten Klasse; einige Methoden angemessen reagieren können, wenn es ein bug ist.So, die Methoden, die Rückkehr
null
.null
- Wert deuten auf einen Fehler in deinem code? Wenn Sie es tut, Sie sollten nicht zu fangen, die Ausnahme überhaupt. Und dein code sollte nicht versuchen, auf den zweiten erraten Sie sich. Schreiben Sie einfach, was klar und prägnant auf der Annahme, dass es funktionieren wird. Eine Kette von Methodenaufrufen klar und prägnant? Dann benutzen Sie einfach die.null
Wert anzugeben ungültige Eingabe an Ihr Programm? Wenn es funktioniert, eineNullPointerException
ist nicht eine entsprechende Ausnahme zu werfen, weil es konventionell ist reserviert für Anzeige-bugs. Sie wollen wahrscheinlich werfen Sie eine eigene exception abgeleitet vonIllegalArgumentException
(wenn Sie möchten, eine ungeprüfte Ausnahme) oderIOException
(wenn Sie möchten, eine checked exception). Ist Ihr Programm erforderlich, um eine detaillierte syntax-Fehlermeldungen, wenn es ungültige Eingabe? Wenn dem so ist, überprüfen Sie nach jeder Methode für einenull
Rückgabewert dann werfen Sie einen geeigneten Diagnose-Ausnahme ist die einzige Sache, die Sie tun können. Wenn Ihr Programm nicht verpflichtet ist, detaillierte Diagnostik, die Verkettung der Methodenaufrufe zusammen, fangen alleNullPointerException
und dann werfen Sie Ihre benutzerdefinierte Ausnahme ist die klarste und prägnanteste.Eine der Antworten, die behauptet, dass die verkettete Methodenaufrufe gegen die Gesetz von Demeter und somit schlecht sind. Diese Behauptung ist falsch.
Nicht fangen
NullPointerException
. Sie weiß nicht, wo es herkommt (ich weiß, es ist nicht wahrscheinlich, in Ihrem Fall aber vielleicht etwas anderes warf ihn) und es ist langsam.Sie möchten auf das angegebene Feld und für jedes andere Feld nicht null ist. Dies ist eine perfekte Gültiger Grund, um zu überprüfen, in jedem Bereich. Ich würde wahrscheinlich prüfen es in einer wenn-dann-erstellen Sie eine Methode für die Lesbarkeit. Wie andere darauf hingewiesen, bereits Rückgabe -1 ist sehr oldschool, aber ich weiß nicht, ob Sie einen Grund haben, oder nicht (z.B. Gespräch auf ein anderes system).
Edit: Es ist fraglich, ob es disobeyes das Gesetz Von Demeter, da die WsObject ist wohl nur eine Daten-Struktur (überprüfen https://stackoverflow.com/a/26021695/1528880).
Wenn Sie nicht wollen, zu überarbeiten Sie den code, und Sie können die Verwendung von Java 8 ist es möglich, verwenden Sie die Methode Referenzen.
Eine einfache demo erste (entschuldigen Sie die statische innere Klassen)
Ausgabe
Die Schnittstelle
Getter
ist nur eine funktionale Schnittstelle, können Sie alle gleichwertig.GetterResult
Klasse, Zugriffsmethoden beraubt, für Klarheit, halten Sie das Ergebnis der get-Kette, falls vorhanden, oder der index des letzten getter aufgerufen.Die Methode
getterChain
ist eine einfache, boilerplate-code, generiert werden können automatisch (oder manuell wenn erforderlich).Ich strukturierte Sie den code so, dass das wiederholte blockieren, ist selbstverständlich.
Dies ist keine perfekte Lösung, da Sie noch brauchen, um eine überlastung der
getterChain
pro Anzahl der Getter.Ich würde Umgestaltung des Codes statt, aber wenn nicht und Sie finden Sie Ihr selbst mit langen getter-Ketten Häufig können Sie darüber nachdenken, eine Klasse mit den überladungen, die aus 2 bis, sagen wir, 10, get.
Wie schon andere gesagt haben, respektieren das Gesetz von Demeter ist definitiv Teil der Lösung. Ein weiterer Teil, wo immer möglich, ist zu ändern Sie die verketteten Methoden, so dass Sie nicht zurück
null
. Sie können vermeiden, Rückkehrnull
indem anstelle der Rückgabe eine leereString
eine leereCollection
oder andere dummy-Objekt, Mittel oder tut, was der Anrufer tun würde, mitnull
.Möchte ich hinzufügen, eine Antwort, die den Fokus auf die Bedeutung der Fehler -. Null exception in sich selbst nicht bieten jeglichen Sinn voller Fehler. Also ich würde raten, um zu vermeiden Umgang mit Ihnen direkt.
Es gibt Tausende Fälle, in denen der code schief gehen kann: kann keine Verbindung zur Datenbank, E /a-Ausnahme, Netzwerk-Fehler... Wenn man sich mit Ihnen eins nach dem anderen (wie der null-check hier), es wäre zu viel Aufwand.
In den code:
Selbst wenn man weiß, welches Feld null ist, haben Sie keine Idee über das, was schief geht. Vielleicht Bar ist null, aber ist zu erwarten? Oder ist es ein Daten-Fehler??? Denken Sie über Menschen, die Lesen Ihren code
Wie in xenteros die Antwort, ich würde vorschlagen mit benutzerdefinierte unchecked exception. Zum Beispiel in dieser situation: Foo null sein kann (gültige Daten), aber die Bar und Baz sollte nie null (ungültige Daten)
Den code neu geschrieben werden kann:
NullPointerException
ist eine Laufzeit-Ausnahme, also generell wird nicht empfohlen, es zu fangen, aber, es zu vermeiden.Haben Sie um die Ausnahme zu fangen, wo immer Sie möchten, rufen Sie die Methode (oder es wird zu propagieren, bis der Stapel). Dennoch, wenn in Ihrem Fall können Sie zu arbeiten halten, mit das Ergebnis mit dem Wert " -1 " und Sie sind sicher, dass es nicht propagieren, weil Sie nicht mit jedem der "Stücke", die null sein darf, dann scheint es mir Recht sein, es zu fangen
Edit:
Ich Stimme mit dem späteren Antwort von @xenteros, es wird besser sein, starten Sie Ihren eigenen Ausnahme statt die Rückgabe -1, können Sie nennen es
InvalidXMLException
zum Beispiel.Verfolge diesen Beitrag seit gestern.
Ich habe Kommentierung/Abstimmung die Kommentare, die sagt, fangen NPE ist schlecht. Hier ist der Grund, warum ich getan haben, dass.
Ausgabe
3.216
0.002
Sehe ich einen klaren Sieger hier. Wenn Prüfungen ist übrigens auch weniger teuer als abfangen einer Ausnahme. Ich habe gesehen, dass Java-8 Weg, das zu tun. Wenn man bedenkt, dass 70% der aktuellen Anwendungen laufen immer noch auf Java 7 ich bin das hinzufügen dieser Antwort.
Bottom Line Für jede geschäftskritische Anwendungen, Umgang mit NPE ist teuer.
Wenn die Effizienz ein Thema ist, dann wird der "catch" - option berücksichtigt werden sollten.
Wenn 'fangen' kann nicht verwendet werden, denn es würde propagieren (wie erwähnt von 'SCouto'), dann verwenden Sie lokale Variablen, um zu vermeiden, mehrere Aufrufe von Methoden
getFoo()
,getBar()
undgetBaz()
.Ist es eine überlegung Wert, um erstellen Sie Ihre eigene Ausnahme. Nennen wir es MyOperationFailedException. Sie können werfen Sie stattdessen zurückgeben eines Wertes. Das Ergebnis wird das gleiche sein - Sie werden beenden Sie die Funktion, aber Sie nicht zurückkehren, hart-codierten Wert -1, was den Java-anti-pattern. In Java verwenden wir Ausnahmen.
EDIT:
Gemäß der Diskussion in den Kommentaren lassen Sie mich etwas hinzufügen zu meinen vorherigen Gedanken. In diesem code gibt es zwei Möglichkeiten. Einer ist, dass Sie akzeptieren null-und das andere ist, dass es ein Fehler ist.
Wenn es ein Fehler ist und es Auftritt, können Sie das Debuggen des Codes mit anderen Strukturen, die für debugging-Zwecke, wenn die Haltepunkte sind nicht genug.
Wenn es akzeptabel ist, Sie kümmern sich nicht darum, wo diese null erschien. Wenn Sie dies tun, Sie sollten nicht definitiv Kette diese Anforderungen.
Die Methode, die Sie haben, ist langwierig, aber sehr gut lesbar. Wenn ich einen neuen Entwickler kommen auf Ihre code-Basis, die ich sehen konnte, was Sie Taten Recht schnell. Die meisten der anderen Antworten (auch Fang die Ausnahme) nicht zu sein scheinen die Dinge mehr lesbar und einige machen es weniger lesbar meiner Meinung nach.
Gegeben, dass Sie wahrscheinlich don T haben die Kontrolle über die generierte Quelle und vorausgesetzt, dass Sie wirklich brauchen nur Zugriff auf ein paar tief geschachtelte Felder, hier und da, dann würde ich empfehlen, einwickeln jedes tief verschachtelten Zugriff auf eine Methode.
Wenn Sie finden, sich selbst zu schreiben eine Menge von diesen Methoden, oder wenn Sie finden, sich selbst geneigt zu machen, diese öffentliche, statische Methoden, dann würde ich erstellen Sie eine separate Objekt-Modell, nested, wie Sie möchten, mit nur den Bereichen, die Sie interessieren, und konvertieren von web services Objekt Modell-Objekt Modell.
Sind, wenn Sie die Kommunikation mit einem remote-web-service es ist sehr typisch für einen "remote domain" und eine "application domain", und wechseln Sie zwischen den beiden. Die remote-Domäne ist Häufig begrenzt durch das web-Protokoll (zum Beispiel, können Sie nicht senden helper-Methoden hin und her in einer reinen Rest-Dienst und tief verschachtelten Objekt-Modelle üblich sind, zu vermeiden, mehrere API-Aufrufe) und damit nicht ideal für den direkten Einsatz in Ihrem client.
Beispiel:
durch die Anwendung des Gesetz von Demeter,
Geben Antwort, die scheint, von allen anderen unterscheidet.
Grund :
Für Sie Ihren code leicht zu Lesen versuchen, diese für die überprüfung der Bedingungen :
EDIT :
Anregungen werden geschätzt..!!
wsObject
wird mit dem Rückgabewert von Webservice..!! Der Service wird aufgerufen und schonwsObject
erhalten eine langeXML
- Daten als webservice Antwort..!! Es gibt also nichts wie server, der sich auf einem anderen Kontinent, weilgetFoo()
ist nur ein element immer get-Methode nicht einem Webservice-Aufruf..!! @xenterosgetFoo
,getBar
,getBaz
. das einzige, was wir bekommen können, von der Frage, istgetFoo().getBar().getBaz().getInt()
ist ein Integer.. Das ist der Grund, warum ich die nicht verwendeten Variablen hier..!!Schrieb ich eine Klasse namens
Snag
können Sie definieren einen Pfad zu navigieren durch einen Baum von Objekten. Hier ist ein Beispiel zu Ihrer Verwendung:Bedeutung, dass die Instanz
ENGINE_NAME
würde effektiv nennenCar?.getEngine()?.getName()
auf die Instanz übergeben, und zurücknull
wenn keine Referenz zurückgegebennull
:Es ist nicht veröffentlicht, Maven, aber wenn jemand findet das nützlich ist es hier (ohne Garantie natürlich!)
Es ist ein bisschen einfach, aber es scheint, um den job zu erledigen. Natürlich, es ist mehr veraltet, die mit neueren Versionen von Java und anderen JVM-Sprachen, die Unterstützung einer sicheren navigation oder
Optional
.