Oft finde ich mich beim Abrufen eines Wertes aus einer Datenhierarchie auf Null überprüft, um NullPointerExceptions zu vermeiden, die meiner Meinung nach fehleranfällig sind und viel Boilerplate erfordern.
Ich habe eine sehr einfache Routine geschrieben, mit der ich die Nullprüfung beim Abrufen eines Objekts überspringen kann ...
public final class NoNPE {
public static <T> T get(NoNPEInterface<T> in) {
try {
return in.get();
} catch (NullPointerException e) {
return null;
}
}
public interface NoNPEInterface<T> {
T get();
}
}
Ich benutze es ein bisschen so ...
Room room = NoNPE.get(() -> country.getTown().getHouses().get(0).getLivingRoom());
Das obige führt dazu, dass ich ein Room-Objekt oder eine Null erhalte, ohne alle übergeordneten Ebenen überprüfen zu müssen.
Was haltet ihr von dem oben genannten? Schaffe ich ein problematisches Muster? Gibt es Ihrer Meinung nach einen besseren Weg, dies zu tun?
java.util.Optional
anstelle von Nullen fehlende Daten darstellt. Dies bietet praktische Hilfsprogramme sowohl für den beschriebenen Fall als auch für Fälle, in denen Sie mit StandarddatenOption
(oderMaybe
) Monade wiederentdeckt :)Antworten:
Ihre Lösung ist sehr klug. Das Problem, das ich sehe, ist die Tatsache, dass Sie nicht wissen, warum Sie eine haben
null
? War es, weil das Haus keine Zimmer hatte? War es, weil die Stadt keine Häuser hatte? War es, weil das Land keine Städte hatte? War es, weil esnull
aufgrund eines Fehlers eine 0-Position in der Sammlung gab, selbst wenn sich Häuser auf Position 1 und höher befanden?Wenn Sie die
NonPE
Klasse in großem Umfang verwenden, treten schwerwiegende Fehlerbehebungsprobleme auf. Ich denke, es ist besser zu wissen, wo genau die Kette gebrochen ist, als im Stillennull
einen Fehler zu finden, der einen tieferen Fehler verbergen könnte.Auch verletzt dies das Gesetz von Demeter :
country.getTown().getHouses().get(0).getLivingRoom()
. Wenn Sie gegen einen guten Grundsatz verstoßen, müssen Sie in den meisten Fällen unorthodoxe Lösungen implementieren, um das Problem zu lösen, das durch einen Verstoß gegen diesen Grundsatz verursacht wird.Meine Empfehlung ist, dass Sie es mit Vorsicht verwenden und versuchen, den Konstruktionsfehler zu beheben, der dazu führt, dass Sie im Zug Wrack-Antimuster haben müssen (damit Sie es nicht
NonPE
überall verwenden müssen). Andernfalls können Fehler auftreten, die nur schwer zu erkennen sind.quelle
Option
Monade verwenden, ist es Ihnen im Allgemeinen egal, wo in der Kette der fehlende Wert ist. Wenn Sie sich dafür interessieren, würden Sie wahrscheinlich einen anderen Typ verwenden, wie zEither
.?.
und?[]
Operatoren. Ein Beispiel dafür, wann Sie so etwas verwenden möchten, sind hierarchische serverseitige Einstellungen.var shouldDoThing = settings?.a?.b?.c ?? defaultSetting;
Wen interessiert es, warum ein Teil davon null war? Möglicherweise konnten Sie die Einstellungen nicht abrufen. Vielleicht haben Sie beschlossen, einen Teil der Einstellungen zu entfernen. In jedem Fall können Sie sich nie wirklich darauf verlassen, die Servereinstellungen abzurufen. Daher ist eine Standardeinstellung in der Regel eine gute Idee, und es ist unwahrscheinlich, dass Sie die tatsächliche Einstellung nicht abrufen können, es sei denn, dies geschieht sehr häufig, wenn dies nicht der Fall ist .settings.a.b.c
. Andererseits ist dies ein einzelnes Beispiel.Die Idee ist gut, wirklich gut. Da es die Java 8-
Optional
Typen gibt, finden Sie eine ausführliche Erläuterung unter Java Optional type . Ein Beispiel für das, was Sie gepostet haben, istUnd weiter.
quelle
Optional
ist die lesbarere Lösung der beiden, wenn auch nur, weil es - anders als Ihr Vorschlag - eine sehr verbreitete Redewendung ist. Es ist noch prägnanter als deins!Ihre Methode funktioniert gut genug für den beabsichtigten Zweck, obwohl sie
null
s zurückgibt, wenn Sie einNullPointerException
schlechtes Design hören.Vermeiden Sie
null
s, wenn Sie können, und geben Sie sie nur weiter, wenn sie etwas darstellen oder eine besondere Bedeutung haben, und geben Sie sie nur zurück, wenn sie etwas darstellen / bedeuten - andernfalls sollten Sie a werfenNullPointerException
. Dies vermeidet Fehler und Verwirrung. Wenn einObject
nicht sein solltenull
,NullPointer
sollte ein geworfen werden. Wenn ein Objekt vorhanden sein kann, wird beimnull
Übergeben nichts schief gehen. Andernfalls funktioniert die obige Methode.quelle
Ich kann deinen Schmerz fühlen, aber die vorgeschlagene Lösung ist eine schlechte Idee.
NoNPE.get
.Optional.map
ist es das , wonach Sie suchen.Als Randnotiz
NoNPEInterface
ist ein Duplikat vonjava.util.function.Supplier
.In einigen Fällen können Sie die Verwendung von Ausdrucksauswertungs-Utils in Betracht ziehen, die in vielen Frameworks vorhanden sind (zum Beispiel: EL, SpEL):
quelle