Die Verwendung requireNonNull()als erste Anweisungen in einer Methode ermöglicht es, die Ursache der Ausnahme sofort / schnell zu identifizieren.
Die Stapelverfolgung zeigt deutlich an, dass die Ausnahme sofort nach Eingabe der Methode ausgelöst wurde, da der Aufrufer die Anforderungen / den Vertrag nicht eingehalten hat.
Das Übergeben eines nullObjekts an eine andere Methode kann zwar jeweils eine Ausnahme hervorrufen, die Ursache des Problems kann jedoch komplizierter zu verstehen sein, da die Ausnahme in einem bestimmten Aufruf des nullObjekts ausgelöst wird , der möglicherweise viel weiter entfernt ist.
Hier ist ein konkretes und reales Beispiel, das zeigt, warum wir es vorziehen müssen, im Allgemeinen schnell zu scheitern und insbesondere Object.requireNonNull()Parameter zu verwenden oder auf irgendeine Weise eine Null-Null-Prüfung für Parameter durchzuführen, die so konzipiert sind, dass dies nicht der Fall ist null.
Angenommen , eine DictionaryKlasse , die ein komponiert LookupServiceund ein Listvon Stringdarstellt Wörter enthalten in. Diese Felder sind so konzipiert, dass nicht , nullund eine davon ist in den vergangen Dictionary Konstruktor.
Nehmen wir nun eine "schlechte" Implementierung Dictionaryohne nullÜberprüfung im Methodeneintrag an (hier ist das der Konstruktor):
public class Dictionary {
private final List<String> words;
private final LookupService lookupService;
public Dictionary(List<String> words) {
this.words = this.words;
this.lookupService = new LookupService(words);
}
public boolean isFirstElement(String userData) {
return lookupService.isFirstElement(userData);
}
}
public class LookupService {
List<String> words;
public LookupService(List<String> words) {
this.words = words;
}
public boolean isFirstElement(String userData) {
return words.get(0).contains(userData);
}
}
Rufen wir nun den DictionaryKonstruktor mit einer nullReferenz für den wordsParameter auf:
Dictionary dictionary = new Dictionary(null);
// exception thrown lately : only in the next statement
boolean isFirstElement = dictionary.isFirstElement("anyThing");
Die JVM wirft die NPE auf diese Aussage:
return words.get(0).contains(userData);
Ausnahme im Thread "main" java.lang.NullPointerException
bei LookupService.isFirstElement (LookupService.java:5)
bei Dictionary.isFirstElement (Dictionary.java:15)
bei Dictionary.main (Dictionary.java:22)
Die Ausnahme wird in der LookupServiceKlasse ausgelöst, während der Ursprung weit früher liegt (der DictionaryKonstruktor). Dies macht die allgemeine Problemanalyse viel weniger offensichtlich.
Ist words null? Ist words.get(0) null? Beide ? Warum sind das eine, das andere oder vielleicht beide null? Ist es ein Codierungsfehler in Dictionary(Konstruktor? Aufgerufene Methode?)? Ist es ein Codierungsfehler in LookupService? (Konstruktor? aufgerufene Methode?)?
Schließlich müssen wir mehr Code untersuchen, um den Fehlerursprung zu finden, und in einer komplexeren Klasse möglicherweise sogar einen Debugger verwenden, um leichter zu verstehen, was passiert ist.
Aber warum wird eine einfache Sache (ein Mangel an Nullprüfung) zu einem komplexen Problem?
Weil wir zugelassen haben, dass der anfängliche Fehler / Mangel bei einem bestimmten Komponentenleck bei niedrigeren Komponenten erkennbar ist.
Stell dir das vorLookupService kein lokaler Dienst, sondern ein Remote-Dienst oder eine Bibliothek eines Drittanbieters mit wenigen Debugging-Informationen, oder stellen Sie sich vor, Sie hätten nicht 2 Ebenen, sondern 4 oder 5 Ebenen von Objektaufrufen, bevor nulldiese erkannt wurden? Das Problem wäre noch komplexer zu analysieren.
Der Weg zu bevorzugen ist also:
public Dictionary(List<String> words) {
this.words = Objects.requireNonNull(words);
this.lookupService = new LookupService(words);
}
Auf diese Weise keine Kopfschmerzen: Wir erhalten die Ausnahme ausgelöst, sobald diese empfangen wird:
// exception thrown early : in the constructor
Dictionary dictionary = new Dictionary(null);
// we never arrive here
boolean isFirstElement = dictionary.isFirstElement("anyThing");
Ausnahme im Thread "main" java.lang.NullPointerException
at java.util.Objects.requireNonNull (Objects.java:203)
at com.Dictionary. (Dictionary.java:15)
at com.Dictionary.main (Dictionary.java:24)
Beachten Sie, dass ich hier das Problem mit einem Konstruktor veranschaulicht habe, ein Methodenaufruf jedoch dieselbe Nicht-Null-Prüfbedingung haben kann.