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 null
Objekts 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 null
Objekts 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 Dictionary
Klasse , die ein komponiert LookupService
und ein List
von String
darstellt Wörter enthalten in. Diese Felder sind so konzipiert, dass nicht , null
und eine davon ist in den vergangen Dictionary
Konstruktor.
Nehmen wir nun eine "schlechte" Implementierung Dictionary
ohne 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 Dictionary
Konstruktor mit einer null
Referenz für den words
Parameter 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 LookupService
Klasse ausgelöst, während der Ursprung weit früher liegt (der Dictionary
Konstruktor). 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 null
diese 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.