Java: Überprüfung auf Null in verschachtelten Klassen vermeiden (Deep Null-Prüfung)
Lesezeit: 7 Minuten
lappall
Stellen Sie sich vor, ich habe eine Klassenfamilie. Es enthält eine Personenliste. Jede (Klassen-)Person enthält eine (Klassen-)Adresse. Jede (Klassen-)Adresse enthält eine (Klassen-)Postleitzahl. Jede “Zwischenklasse” kann null sein.
Gibt es also eine einfache Möglichkeit, zu PostalCode zu gelangen, ohne bei jedem Schritt auf null prüfen zu müssen? dh gibt es eine Möglichkeit, den folgenden Daisy-Chaining-Code zu vermeiden? Ich weiß, dass es keine “native” Java-Lösung gibt, aber ich hatte gehofft, ob jemand eine Bibliothek oder so etwas kennt. (geprüft Commons & Guava und nichts gesehen)
if(family != null) {
if(family.getPeople() != null) {
if(family.people.get(0) != null) {
if(people.get(0).getAddress() != null) {
if(people.get(0).getAddress().getPostalCode() != null) {
//FINALLY MADE IT TO DO SOMETHING!!!
}
}
}
}
}
Nein, die Struktur kann nicht geändert werden. Es stammt von einem Dienst, über den ich keine Kontrolle habe.
Nein, ich kann Groovy und seinen praktischen “Elvis”-Operator nicht verwenden.
Nein, ich möchte lieber nicht auf Java 8 warten 😀
Ich kann nicht glauben, dass ich der erste Entwickler bin, der es satt hat, solchen Code zu schreiben, aber ich konnte keine Lösung finden.
Tut mir leid, du steckst fest. Einige Leute verwenden den trinären Bedingungsoperator, um ihn etwas weniger dicht zu machen, aber es ist immer noch derselbe Bytecode, nur schwerer zu lesen.
– Paul Tomblin
30. April 2012 um 22:32 Uhr
“Ich kann nicht glauben, dass ich der erste Entwickler bin, der es satt hat, solchen Code zu schreiben„Nun, bist du nicht.
– Benutzer1329572
30. April 2012 um 22:34 Uhr
Trotz all der Antworten, die Ihnen sagen, dass Sie Nullprüfungen ignorieren und einfach versuchen sollen, a zu fangen NullPointerException, tu es nicht! Ihr Code mag ein Dorn im Auge sein, aber das Auslösen einer Ausnahme ist eine teure Operation, die Sie immer vermeiden möchten, wenn Sie können.
– Jeffrey
30. April 2012 um 22:47 Uhr
Berücksichtigen Sie auch all die guten Dinge, die Sie in “else”-Klauseln tun können, wenn Sie sie einfügen – Fehlermeldungen, alternative Codepfade usw. Angesichts all dessen wird es nicht so schlecht aussehen.
Wenn Sie eine .map-Implementierung sehen, verwendet sie Objects.requireNonNull(mapper); und diese Methode löst nullpointerexception aus, wenn der Mapper null wird.
– Anirudh
27. Februar 2020 um 10:18 Uhr
@Anirudh der Mapper ist in diesem Fall die Methodenreferenz und ist niemals null. Der vom Mapper zurückgegebene Wert kann null sein, und in diesem Fall gibt die Map Optional.empty() zurück.
Dank an Kurzschlussauswertungdies ist auch sicher, da die zweite Bedingung nicht ausgewertet wird, wenn die erste falsch ist, die dritte nicht ausgewertet wird, wenn die zweite falsch ist, …. und Sie erhalten kein NPE, weil dies der Fall ist.
Falls Sie Java8 verwenden, können Sie Folgendes verwenden:
resolve(() -> people.get(0).getAddress().getPostalCode());
.ifPresent(System.out::println);
:
public static <T> Optional<T> resolve(Supplier<T> resolver) {
try {
T result = resolver.get();
return Optional.ofNullable(result);
}
catch (NullPointerException e) {
return Optional.empty();
}
}
Diese Lösung beruht auf dem Fangen der NPE, die sehr schlecht abschneiden wird.
– mojoken
22. September 2017 um 1:33 Uhr
Ich bin dafür. Kann jemand erklären, warum es schlecht ist? Liegt es daran, dass die Getter aufgrund eines anderen Fehlers intern durch eine NPE gehen und maskiert werden?
– daltonfury42
16. Juni 2021 um 5:20 Uhr
Paul Tomblin
Das Beste, was Sie erreichen können, ist, die Abkürzungsregeln in Bedingungen zu nutzen:
if(family != null && family.getPeople() != null && family.people.get(0) != null && family.people.get(0).getAddress() != null && family.people.get(0).getAddress().getPostalCode() != null) {
//FINALLY MADE IT TO DO SOMETHING!!!
}
Übrigens ist es eine schreckliche Idee, eine Ausnahme abzufangen, anstatt die Bedingung im Voraus zu testen.
Das Beste daran ist, dass die statischen Methoden mit jeder Funktion wiederverwendbar sind 🙂
Anstatt null zu verwenden, könnten Sie eine Version des Entwurfsmusters „Nullobjekt“ verwenden. Zum Beispiel:
public class Family {
private final PersonList people;
public Family(PersonList people) {
this.people = people;
}
public PersonList getPeople() {
if (people == null) {
return PersonList.NULL;
}
return people;
}
public boolean isNull() {
return false;
}
public static Family NULL = new Family(PersonList.NULL) {
@Override
public boolean isNull() {
return true;
}
};
}
import java.util.ArrayList;
public class PersonList extends ArrayList<Person> {
@Override
public Person get(int index) {
Person person = null;
try {
person = super.get(index);
} catch (ArrayIndexOutOfBoundsException e) {
return Person.NULL;
}
if (person == null) {
return Person.NULL;
} else {
return person;
}
}
//... more List methods go here ...
public boolean isNull() {
return false;
}
public static PersonList NULL = new PersonList() {
@Override
public boolean isNull() {
return true;
}
};
}
public class Person {
private Address address;
public Person(Address address) {
this.address = address;
}
public Address getAddress() {
if (address == null) {
return Address.NULL;
}
return address;
}
public boolean isNull() {
return false;
}
public static Person NULL = new Person(Address.NULL) {
@Override
public boolean isNull() {
return true;
}
};
}
etc etc etc
Dann kann Ihre if-Anweisung werden:
if (!family.getPeople().get(0).getAddress().getPostalCode.isNull()) {...}
Es ist suboptimal, weil:
Sie stecken fest, NULL-Objekte für jede Klasse zu erstellen,
Es ist schwierig, diese Objekte generisch zu machen, also müssen Sie eine Null-Objekt-Version jeder Liste, Karte usw. erstellen, die Sie verwenden möchten, und
Es gibt möglicherweise einige lustige Probleme mit der Unterklassenbildung und der Verwendung von NULL.
Aber wenn du deine wirklich hasst == nulls, das ist ein Ausweg.
Gemeinschaft
Obwohl dieser Beitrag fast fünf Jahre alt ist, habe ich vielleicht eine andere Lösung für die uralte Frage, wie man damit umgeht NullPointerExceptions.
Da noch viel Legacy-Code verwendet wird, verwenden Sie Java 8 und Optional ist nicht immer eine Option.
Wann immer es um tief verschachtelte Klassen geht (JAXB, SOAP, JSON, was auch immer …) und Gesetz der Demeter nicht angewendet wird, müssen Sie im Grunde alles überprüfen und sehen, ob möglicherweise NPEs lauern.
Meine vorgeschlagene Lösung strebt nach Lesbarkeit und sollte nicht verwendet werden, wenn nicht mindestens 3 oder mehr verschachtelte Klassen beteiligt sind (wenn ich verschachtelt sage, meine ich nicht Verschachtelte Klassen im formellen Kontext). Da Code mehr gelesen als geschrieben wird, macht ein kurzer Blick auf den linken Teil des Codes seine Bedeutung klarer als die Verwendung tief verschachtelter if-else-Anweisungen.
Wenn Sie den Else-Teil benötigen, können Sie dieses Muster verwenden:
Bestimmte IDEs brechen diese Formatierung, es sei denn, Sie weisen sie an, dies nicht zu tun (siehe diese Frage).
Ihre Bedingungen müssen invertiert werden – Sie teilen dem Code mit, wann er unterbrochen werden soll, nicht wann er fortgesetzt werden soll.
Eine weitere Sache – Ihr Code ist immer noch anfällig für Brüche. Sie müssen verwenden if(family.getPeople() != null && !family.getPeople().isEmpty()) als erste Zeile in Ihrem Code, andernfalls löst eine leere Liste eine NPE aus.
13815700cookie-checkJava: Überprüfung auf Null in verschachtelten Klassen vermeiden (Deep Null-Prüfung)yes
Tut mir leid, du steckst fest. Einige Leute verwenden den trinären Bedingungsoperator, um ihn etwas weniger dicht zu machen, aber es ist immer noch derselbe Bytecode, nur schwerer zu lesen.
– Paul Tomblin
30. April 2012 um 22:32 Uhr
“Ich kann nicht glauben, dass ich der erste Entwickler bin, der es satt hat, solchen Code zu schreiben„Nun, bist du nicht.
– Benutzer1329572
30. April 2012 um 22:34 Uhr
Trotz all der Antworten, die Ihnen sagen, dass Sie Nullprüfungen ignorieren und einfach versuchen sollen, a zu fangen
NullPointerException
, tu es nicht! Ihr Code mag ein Dorn im Auge sein, aber das Auslösen einer Ausnahme ist eine teure Operation, die Sie immer vermeiden möchten, wenn Sie können.– Jeffrey
30. April 2012 um 22:47 Uhr
Berücksichtigen Sie auch all die guten Dinge, die Sie in “else”-Klauseln tun können, wenn Sie sie einfügen – Fehlermeldungen, alternative Codepfade usw. Angesichts all dessen wird es nicht so schlecht aussehen.
– Mazaneicha
30. April 2012 um 23:03 Uhr
Wenn Sie Brototype nur für Java portieren könnten … github.com/letsgetrandy/brototype
– jonS90
8. Oktober 2014 um 18:25 Uhr