IllegalArgumentException oder NullPointerException für einen Nullparameter? [geschlossen]

547

Ich habe eine einfache Setter-Methode für eine Eigenschaft und nullist für diese bestimmte Eigenschaft nicht geeignet. Ich war in dieser Situation immer hin und her gerissen: Soll ich einen IllegalArgumentExceptionoder einen werfen NullPointerException? Von den Javadocs scheinen beide angemessen. Gibt es eine Art verstandenen Standard? Oder ist dies nur eines der Dinge, die Sie tun sollten, was Sie bevorzugen, und beide sind wirklich richtig?

Mike Stone
quelle

Antworten:

299

Es scheint wie ein IllegalArgumentExceptiongenannt wird , wenn Sie nicht wollen , nullein zulässiger Wert sein, und das NullPointerExceptionwürde geworfen werden , wenn Sie versuchten , verwenden eine Variable, die erweist sich als null.

Greg Hurlman
quelle
33
Die folgenden Antworten auf diese Frage liefern überzeugende Argumente dafür, dass NullPointerException die richtige Ausnahme ist: stackoverflow.com/a/8160/372926 ; stackoverflow.com/a/8196334/372926 ; und stackoverflow.com/a/6358/372926 .
SamStephens
2
IllegalArgumentExceptionsteht im Widerspruch zu Javas Objects.requireNonNull (T) und Guavas Preconditions.checkNotNull (T), die a auslösenNullPointerException . Die richtige Antwort ist jedoch definitiv, IllegalArgumentException wie in Jason Cohens hervorragender Antwort und seinem Kommentarbereich erläutert .
Matoni
417

Sie sollten aus folgenden Gründen IllegalArgumentException(IAE) und nicht NullPointerException(NPE) verwenden:

Zunächst listet der NPE JavaDoc explizit die Fälle auf, in denen NPE angemessen ist. Beachten Sie, dass alle von ihnen zur Laufzeit ausgelöst werden, wenn nullsie nicht ordnungsgemäß verwendet werden. Im Gegensatz dazu könnte das IAE JavaDoc nicht klarer sein: " Wird geworfen, um anzuzeigen, dass einer Methode ein illegales oder unangemessenes Argument übergeben wurde." Ja, das bist du!

Zweitens, wenn Sie eine NPE in einer Stapelverfolgung sehen, was nehmen Sie an? Wahrscheinlich hat jemand a dereferenziert null. Wenn Sie IAE sehen, nehmen Sie an, dass der Aufrufer der Methode oben im Stapel einen unzulässigen Wert übergeben hat. Wiederum ist die letztere Annahme wahr, die erstere ist irreführend.

Drittens, da IAE eindeutig für die Validierung von Parametern ausgelegt ist, müssen Sie es als Standardauswahl für Ausnahmen annehmen. Warum sollten Sie stattdessen NPE wählen? Sicherlich nicht für ein anderes Verhalten - erwarten Sie wirklich, dass das Aufrufen von Code NPEs getrennt von IAE abfängt und dadurch etwas anderes bewirkt? Versuchen Sie, eine spezifischere Fehlermeldung zu übermitteln? Sie können dies jedoch trotzdem im Text der Ausnahmemeldung tun, wie Sie es für alle anderen falschen Parameter tun sollten.

Viertens sind alle anderen falschen Parameterdaten IAE. Warum also nicht konsistent sein? Warum ist ein Illegales nullso besonders, dass es eine separate Ausnahme von allen anderen Arten illegaler Argumente verdient?

Schließlich akzeptiere ich das Argument anderer Antworten, dass Teile der Java-API NPE auf diese Weise verwenden. Die Java-API ist jedoch nicht mit allem vereinbar, von Ausnahmetypen bis hin zu Namenskonventionen. Daher denke ich, dass das blinde Kopieren (Ihres Lieblingsteils) der Java-API nicht gut genug ist, um diese anderen Überlegungen zu übertreffen.

Jason Cohen
quelle
119
Effektive Java 2nd Edition, Punkt 60: "Wahrscheinlich laufen alle fehlerhaften Methodenaufrufe auf ein unzulässiges Argument oder einen unzulässigen Zustand hinaus, aber andere Ausnahmen werden normalerweise für bestimmte Arten von unzulässigen Argumenten und Zuständen verwendet. Wenn ein Aufrufer in einem Parameter, für den null übergeben wird, null Nullwerte sind verboten. Die Konvention schreibt vor, dass NullPointerException anstelle von IllegalArgumentException ausgelöst wird. Wenn ein Aufrufer einen Wert außerhalb des Bereichs in einem Parameter übergibt, der einen Index in einer Sequenz darstellt, sollte IndexOutOfBoundsException anstelle von IllegalArgumentException ausgelöst werden. "
Gili
33
Das JavaDoc für NPE gibt außerdem Folgendes an: "Anwendungen sollten Instanzen dieser Klasse auslösen, um andere illegale Verwendungen des Null-Objekts anzuzeigen." Dieser könnte klarer sein :(
R. Martinho Fernandes
12
Leider werfen die Validierungsmethoden Validate.notNull(commons lang) und Preconditions.checkNotNull(guava) beide NPE :-(
Aaron Digulla
2
Obwohl Guava auch Preconditions.checkArgument () hat, löst IllegalArgumentException ...
michaelok
16
@AaronDigulla aus den Guava-Dokumenten: "Wir erkennen, dass es viele gültige Argumente dafür gibt, IAE auf ein Nullargument zu werfen. Wenn wir eine Zeitmaschine hätten, die> 15 Jahre zurückreicht, könnten wir sogar versuchen, die Dinge voranzutreiben." Diese Richtung. Wir haben uns jedoch entschlossen, die JDK- und Effective Java-Präferenz von NullPointerException beizubehalten. Wenn Sie fest davon überzeugt sind, dass IAE richtig ist, haben Sie dies immer noch checkArgument(arg != null), nur ohne die Bequemlichkeit, dass es arg zurückgibt, oder Sie können erstellen ein lokales Dienstprogramm für Ihr Projekt. " code.google.com/p/guava-libraries/wiki/IdeaGraveyard
Arto Bendiken
162

Der Standard ist, die zu werfen NullPointerException. Das allgemein unfehlbare "Effective Java" diskutiert dies kurz in Punkt 42 (erste Ausgabe), Punkt 60 (zweite Ausgabe) oder Punkt 72 (dritte Ausgabe) "Bevorzugen Sie die Verwendung von Standardausnahmen":

"Wahrscheinlich laufen alle fehlerhaften Methodenaufrufe auf ein illegales Argument oder einen illegalen Zustand hinaus, aber andere Ausnahmen werden normalerweise für bestimmte Arten von illegalen Argumenten und Zuständen verwendet. Wenn ein Aufrufer in einem Parameter, für den Nullwerte verboten sind, null übergibt, schreibt die Konvention dies vor NullPointerException wird anstelle von IllegalArgumentException ausgelöst. "

GaryF
quelle
95
Ich bin absolut anderer Meinung. NullPointerExceptions sollten nur ausgelöst werden, wenn die JVM versehentlich einer Nullreferenz folgt. Das ist der Unterschied, der Ihnen hilft, wenn Sie um 3 Uhr morgens angerufen werden, um sich den Code anzusehen.
Thorbjørn Ravn Andersen
26
Ich bin nicht unbedingt mit dem Standard einverstanden (ich könnte tatsächlich in beide Richtungen gehen), aber das ist die Standardverwendung im gesamten JDK, daher ist effektives Java der Fall. Ich denke, dies ist ein Fall, in dem Sie entscheiden, ob Sie dem Standard folgen oder das tun, was Sie für richtig halten. Wenn Sie keinen sehr guten Grund haben (und dies kann sich sicherlich qualifizieren), ist es am besten, die Standardpraxis zu befolgen.
GaryF
21
Die Ausnahmeverfolgung zeigt den Punkt der Ausnahme an. Wenn also der Unterschied im Typ der Ausnahme für Sie die Hölle verursacht oder "der Unterschied ist, der Ihnen hilft", machen Sie etwas sehr Falsches.
Jim Balter
8
Fantasien und Sophistik. Gleich unten schreibt MB: "Beachten Sie, dass die Argumente zum Hard-Debugging falsch sind, da Sie NullPointerException natürlich eine Nachricht senden können, die besagt, was null war und warum es nicht null sein sollte. Genau wie bei IllegalArgumentException."
Jim Balter
10
Lassen Sie mich als ursprünglicher Antwortender hier sagen, dass es einfach nicht so wichtig ist. Es garantiert sicherlich keine 6 Jahre Gespräch. Wählen Sie eine aus, je nachdem, was Sie möchten, und seien Sie konsequent. Der Standard ist, wie ich bereits sagte, NPE. Wenn Sie IAE aus welchen Gründen auch immer bevorzugen, entscheiden Sie sich dafür. Sei einfach konsequent.
GaryF
138

Ich war alle dafür, IllegalArgumentExceptionfür Null-Parameter zu werfen , bis ich heute die java.util.Objects.requireNonNullMethode in Java 7 bemerkte . Mit dieser Methode, anstatt:

if (param == null) {
    throw new IllegalArgumentException("param cannot be null.");
}

du kannst tun:

Objects.requireNonNull(param);

und es wird ein geworfen, NullPointerExceptionwenn der Parameter, den Sie übergeben, es ist null.

Angesichts der Tatsache, dass diese Methode mitten in der Sache richtig ist, halte java.utilich ihre Existenz für ein ziemlich starkes Indiz dafür, dass das Werfen NullPointerException"die Java-Methode ist, Dinge zu tun".

Ich denke, ich bin jedenfalls entschieden.

Beachten Sie, dass die Argumente zum Hard-Debugging falsch sind, da Sie natürlich eine Meldung angeben können NullPointerException, was null war und warum es nicht null sein sollte. Genau wie bei IllegalArgumentException.

Ein zusätzlicher Vorteil von NullPointerExceptionist, dass Sie in hochleistungskritischem Code auf eine explizite Überprüfung auf null (und eine NullPointerExceptionmit einer benutzerfreundlichen Fehlermeldung) verzichten und sich einfach darauf verlassen können, dass NullPointerExceptionSie automatisch eine erhalten, wenn Sie eine Methode für null aufrufen Parameter. Vorausgesetzt, Sie rufen eine Methode schnell auf (dh sie schlägt schnell fehl), haben Sie im Wesentlichen den gleichen Effekt, nur nicht ganz so benutzerfreundlich für den Entwickler. In den meisten Fällen ist es wahrscheinlich besser, explizit zu überprüfen und mit einer nützlichen Meldung anzuzeigen, welcher Parameter null war, aber es ist schön, die Option zu haben, dies zu ändern, wenn die Leistung dies erfordert, ohne den veröffentlichten Vertrag der Methode / des Konstruktors zu brechen.

MB.
quelle
14
Guave Preconditions.checkNotNull(arg)wirft auch NPE.
Assylias
14
Dies fügt NullPointerException für illegale Null-ARGUMENTE nicht wirklich mehr Gewicht hinzu. Sowohl das JDK requireNonNull () als auch Guava checkNotNull () können mit jedem Objekt an einer beliebigen Stelle im Code aufgerufen werden. Sie können sie beispielsweise in einer Schleife aufrufen. requireNotNull () und checkNotNull () konnten möglicherweise nicht davon ausgehen, mit einigen Methodenargumenten aufgerufen zu werden, und lösen IllegalArgumentException aus. Beachten Sie, dass Guava auch Preconditions.checkArgument () hat, das IllegalArgumentException auslöst.
Bogdan Calmac
2
Ein fairer Punkt von Bogdan, obwohl ich vermute, dass die typische (und allgemein beabsichtigte) Verwendung von requireNonNull zur Überprüfung von Argumenten dient. Wenn Sie überprüfen müssten, ob etwas in einer Schleife nicht null ist, hätte ich gedacht, dass eine Behauptung der typische Weg ist.
MB.
15
Ich denke, das JavaDoc von Object.requireNonNull () fügt dem Argument Gewicht hinzu: "Diese Methode wurde hauptsächlich für die Parametervalidierung in Methoden und Konstruktoren entwickelt"
Richard Zschech
Beachten Sie, dass das Leistungsargument für implizite Nullprüfungen häufig ungültig ist. Die JIT kann Benutzer-Nullprüfungen erkennen und die folgende implizite Nullprüfung umgehen und / oder denselben Optimierungssatz für beide Arten von Nullprüfungen verwenden. Sehen Sie in diesem Wiki für weitere Informationen, insbesondere: Benutzer geschrieben null Kontrollen sind in den meisten Fällen funktional identisch mit denen von der JVM eingefügt. Wenn Sie in Ihrer Null etwas ausgefalleneres wie benutzerdefinierte Nachrichten tun, gilt diese Optimierung möglicherweise nicht.
BeeOnRope
70

Ich neige dazu, dem Design von JDK-Bibliotheken zu folgen, insbesondere Sammlungen und Parallelität (Joshua Bloch, Doug Lea, diese Leute wissen, wie man solide APIs entwirft). Wie auch immer, viele APIs im JDK werfen proaktiv NullPointerException.

Zum Beispiel das Javadoc für Map.containsKeyStaaten:

@throws NullPointerException, wenn der Schlüssel null ist und diese Zuordnung keine Nullschlüssel zulässt (optional).

Es ist absolut gültig, eine eigene NPE zu werfen. Die Konvention besteht darin, den Parameternamen, der null war, in die Nachricht der Ausnahme aufzunehmen.

Das Muster lautet:

public void someMethod(Object mustNotBeNull) {  
    if (mustNotBeNull == null) {  
        throw new NullPointerException("mustNotBeNull must not be null");  
    }  
}

Was auch immer Sie tun, lassen Sie nicht zu, dass ein schlechter Wert festgelegt wird, und lösen Sie später eine Ausnahme aus, wenn anderer Code versucht, ihn zu verwenden. Das macht das Debuggen zu einem Albtraum. Sie sollten immer das "Fail-Fast" -Prinzip befolgen.

Mark Renouf
quelle
3
Denkanstoß: Möglicherweise ist der Grund dafür, dass NullPointerException IllegalArgumentException nicht erweitert, der, dass Ersteres in Fällen auftreten kann, in denen keine Methodenargumente enthalten sind.
Gili
2
@Gili: Möglicherweise besteht dieses Problem überhaupt erst, weil Java keine Mehrfachvererbung unterstützt. Wenn Java MI unterstützt, können Sie eine Ausnahme auslösen, die sowohl von IllegalArgumentException als auch von NullPointerException erbt.
Lie Ryan
7
Die Nachricht muss das Argument nicht enthalten, da es immer null wäre und Folgendes ergibt: "null darf nicht null sein", nicht sehr nützlich. :-) Ansonsten stimme ich zu, dass Sie eine "reiche" NPE mit einer aussagekräftigen Botschaft erstellen können.
PhiLho
5
Ich muss zustimmen - folgen Sie im Zweifelsfall der Standard-API. Nicht alles in der API ist optimal, aber es wird von Hunderten von Entwicklern gepflegt und iteriert und von Millionen von Programmierern verwendet. In Java 7 haben wir ein weiteres Beispiel für die Verwendung der NPE auf diese Weise. Die Objects.requireNonNull (T obj) -Methode - eindeutig angegeben, um zu überprüfen, ob Objektreferenzen nicht null sind, eindeutig angegeben, um die Parameterüberprüfung in Methoden / Konstruktoren durchzuführen, und eindeutig angegeben, um eine NPE auszulösen, wenn das Objekt null ist. Ende von
flamming_python
44

Hat Jason Cohens Argument gewählt, weil es gut präsentiert wurde. Lassen Sie es mich Schritt für Schritt zerstückeln. ;-);

  • Das NPE JavaDoc sagt ausdrücklich "andere illegale Verwendungen des Null-Objekts" . Wenn es nur auf Situationen beschränkt wäre, in denen die Laufzeit auf eine Null stößt, wenn dies nicht der Fall sein sollte, könnten alle diese Fälle weitaus prägnanter definiert werden.

  • Es kann nicht anders, wenn Sie das Falsche annehmen, aber wenn die Kapselung richtig angewendet wird, sollten Sie sich wirklich nicht darum kümmern oder bemerken, ob eine Null unangemessen dereferenziert wurde oder ob eine Methode eine unangemessene Null erkannt und eine Ausnahme ausgelöst hat.

  • Ich würde NPE aus mehreren Gründen gegenüber IAE wählen

    • Es geht genauer um die Art der illegalen Operation
    • Logik, die fälschlicherweise Nullen zulässt, unterscheidet sich in der Regel stark von Logik, die fälschlicherweise unzulässige Werte zulässt. Wenn ich beispielsweise von einem Benutzer eingegebene Daten überprüfe und einen nicht akzeptablen Wert erhalte, liegt die Ursache für diesen Fehler beim Endbenutzer der Anwendung. Wenn ich eine Null bekomme, ist das ein Programmiererfehler.
    • Ungültige Werte können zu Stapelüberläufen, Speicherfehlern, Parsing-Ausnahmen usw. führen. In der Tat werden die meisten Fehler in einem Methodenaufruf irgendwann als ungültiger Wert angezeigt. Aus diesem Grunde sehe ich IAE als tatsächlich die allgemeinste aller Ausnahmen unter Runtime.
  • Tatsächlich können andere ungültige Argumente zu allen möglichen anderen Ausnahmen führen. UnknownHostException , FileNotFoundException , eine Vielzahl von Syntaxfehlerausnahmen, IndexOutOfBoundsException , Authentifizierungsfehler usw. usw.

Im Allgemeinen bin ich der Meinung, dass NPE sehr bösartig ist, weil es traditionell mit Code in Verbindung gebracht wurde, der nicht dem Fail-Fast-Prinzip folgt . Dies und das Versäumnis des JDK, NPEs mit einer Nachrichtenzeichenfolge zu füllen, haben wirklich eine starke negative Stimmung erzeugt, die nicht begründet ist. In der Tat ist der Unterschied zwischen NPE und IAE aus Laufzeitsicht genau der Name. Aus dieser Perspektive gilt: Je genauer Sie mit dem Namen umgehen, desto klarer wird der Anrufer.

Christopher Smith
quelle
Der Unterschied zwischen den meisten ungeprüften Ausnahmen ist nur der Name.
Thorbjørn Ravn Andersen
20

Es ist eine Frage im Stil des "Heiligen Krieges". Mit anderen Worten, beide Alternativen sind gut, aber die Menschen werden ihre Vorlieben haben, die sie bis zum Tod verteidigen werden.

Steve McLeod
quelle
Nein, es gibt nur eine richtige Antwort auf diese Frage: Verwenden Sie die Ausnahme "IllegalArgument", wenn die Eingabe in die Methode falsch ist. Auch in der Entwicklungsumgebung können Sie Assertions verwenden, um die Gültigkeit der Eingabe zu überprüfen und die richtige Ausnahme
auszulösen
@ Mr.Q Und ich denke, das NullPointerExceptionsollte geworfen werden: Es ist die Konvention, die das JDK verwendet und für Schnittstellen benötigt, es ist spezifischer (genau wie IndexOutOfBoundsExceptionusw.) usw.
Solomon Ucko
kekekekkek ...: D
Yousha Aleayoub
17

Wenn es eine setterMethode ist und an nullsie weitergegeben wird, wäre es meiner Meinung nach sinnvoller, eine zu werfen IllegalArgumentException. A NullPointerExceptionscheint sinnvoller zu sein, wenn Sie versuchen, das tatsächlich zu verwenden null.

Also, wenn Sie es verwenden und es ist null, NullPointer. Wenn es übergeben wird und es ist null, IllegalArgument.

Jeremy Privett
quelle
9

Apache Commons Lang verfügt über eine NullArgumentException , die eine Reihe der hier beschriebenen Aufgaben ausführt: Sie erweitert die IllegalArgumentException und ihr einziger Konstruktor übernimmt den Namen des Arguments, das nicht null sein sollte.

Während ich der Meinung bin, dass das Auslösen einer NullArgumentException oder IllegalArgumentException die außergewöhnlichen Umstände genauer beschreibt, haben meine Kollegen und ich beschlossen, Blochs Rat zu diesem Thema zu widerrufen.

Brian T. Grant
quelle
7
Beachten Sie, dass sie es aus commons-lang3 entfernt haben: apache-commons.680414.n4.nabble.com/…
artbristol
7

Konnte nicht mehr mit dem übereinstimmen, was gesagt wird. Früh scheitern, schnell scheitern. Ziemlich gutes Ausnahme-Mantra.

Die Frage, welche Ausnahme zu werfen ist, ist meistens eine Frage des persönlichen Geschmacks. In meinen Augen scheint IllegalArgumentException spezifischer zu sein als die Verwendung einer NPE, da es mir sagt, dass das Problem mit einem Argument zusammenhängt, das ich an die Methode übergeben habe, und nicht mit einem Wert, der möglicherweise während der Ausführung der Methode generiert wurde.

Meine 2 Cent

Allain Lalonde
quelle
7

Tatsächlich ist die Frage, IllegalArgumentException oder NullPointerException auszulösen, meiner bescheidenen Ansicht nach nur ein "heiliger Krieg" für eine Minderheit mit einem unvollständigen Verständnis der Ausnahmebehandlung in Java. Im Allgemeinen sind die Regeln einfach und wie folgt:

  • Verstöße gegen Argumentbeschränkungen müssen so schnell wie möglich angezeigt werden (-> schnell fehlschlagen), um illegale Zustände zu vermeiden, die viel schwerer zu debuggen sind
  • Im Falle eines ungültigen Nullzeigers aus irgendeinem Grund lösen Sie NullPointerException aus
  • Im Falle eines unzulässigen Array- / Sammlungsindex werfen Sie ArrayIndexOutOfBounds
  • Bei einer negativen Array- / Sammlungsgröße wird NegativeArraySizeException ausgelöst
  • Im Falle eines unzulässigen Arguments, das nicht unter das oben Gesagte fällt und für das Sie keinen anderen spezifischeren Ausnahmetyp haben, werfen Sie IllegalArgumentException als Papierkorb
  • Auf der anderen Seite sollten Sie im Falle einer Einschränkungsverletzung INNERHALB EINES FELDES, die durch einen schnellen Fehler aus einem gültigen Grund nicht vermieden werden konnte, als IllegalStateException oder eine spezifischere geprüfte Ausnahme abfangen und erneut auslösen. Lassen Sie in diesem Fall niemals die ursprüngliche NullPointerException, ArrayIndexOutOfBounds usw. passieren!

Es gibt mindestens drei sehr gute Gründe gegen die Zuordnung aller Arten von Verstößen gegen Argumentbeschränkungen zu IllegalArgumentException, wobei der dritte wahrscheinlich so schwerwiegend ist, dass er den schlechten Stil der Praxis kennzeichnet:

(1) Ein Programmierer kann nicht sicher davon ausgehen, dass alle Fälle von Verstößen gegen Argumentbeschränkungen zu IllegalArgumentException führen, da die große Mehrheit der Standardklassen diese Ausnahme eher als Papierkorb verwendet, wenn keine spezifischere Art von Ausnahme verfügbar ist. Der Versuch, alle Fälle von Verstößen gegen Argumentbeschränkungen IllegalArgumentException in Ihrer API zuzuordnen, führt nur zu Frustration des Programmierers bei der Verwendung Ihrer Klassen, da die Standardbibliotheken meist unterschiedlichen Regeln folgen, die Ihre verletzen, und die meisten Ihrer API-Benutzer sie auch verwenden!

(2) Das Zuordnen der Ausnahmen führt tatsächlich zu einer anderen Art von Anomalie, die durch eine einzelne Vererbung verursacht wird: Alle Java-Ausnahmen sind Klassen und unterstützen daher nur eine einzelne Vererbung. Daher gibt es keine Möglichkeit, eine Ausnahme zu erstellen, die sowohl eine NullPointerException als auch eine IllegalArgumentException darstellt, da Unterklassen nur von der einen oder anderen erben können. Das Auslösen einer IllegalArgumentException im Falle eines Null-Arguments erschwert es API-Benutzern daher, zwischen Problemen zu unterscheiden, wenn ein Programm versucht, das Problem programmgesteuert zu beheben, z. B. indem Standardwerte in eine Aufrufwiederholung eingegeben werden!

(3) Durch das Zuordnen besteht tatsächlich die Gefahr der Fehlermaskierung: Um Verstöße gegen Argumentbeschränkungen in IllegalArgumentException abzubilden, müssen Sie in jeder Methode mit eingeschränkten Argumenten einen äußeren Try-Catch codieren. Das einfache Abfangen von RuntimeException in diesem catch-Block kommt jedoch nicht in Frage, da dies das Risiko birgt, dokumentierte RuntimeExceptions, die von in Ihnen verwendeten libery-Methoden ausgelöst werden, in IllegalArgumentException abzubilden, selbst wenn sie nicht durch Verstöße gegen Argumentbeschränkungen verursacht werden. Sie müssen also sehr spezifisch sein, aber selbst dieser Aufwand schützt Sie nicht vor dem Fall, dass Sie versehentlich eine undokumentierte Laufzeitausnahme einer anderen API (dh einen Fehler) einer IllegalArgumentException Ihrer API zuordnen.

Mit der Standardpraxis hingegen bleiben die Regeln einfach und Ausnahmeursachen bleiben entlarvt und spezifisch. Für den Methodenaufrufer sind die Regeln ebenfalls einfach: - Wenn Sie auf eine dokumentierte Laufzeitausnahme jeglicher Art stoßen, weil Sie einen unzulässigen Wert übergeben haben, wiederholen Sie den Aufruf entweder mit einer Standardeinstellung (für diese speziellen Ausnahmen ist dies erforderlich) oder korrigieren Sie Ihren Code - Wenn Sie andererseits auf eine Laufzeitausnahme stoßen, die für einen bestimmten Satz von Argumenten nicht dokumentiert ist, reichen Sie einen Fehlerbericht bei den Herstellern der Methode ein, um sicherzustellen, dass entweder ihr Code oder ihre Dokumentation behoben ist.

Sascha Baumeister
quelle
6

Die akzeptierte Praxis, wenn Sie die IllegalArgumentException (String-Nachricht) verwenden , um einen Parameter als ungültig zu deklarieren und so viele Details wie möglich anzugeben ... Wenn Sie also sagen, dass ein Parameter null ist, während die Ausnahme nicht null ist, würden Sie etwas tun so was:

if( variable == null )
    throw new IllegalArgumentException("The object 'variable' cannot be null");

Sie haben praktisch keinen Grund, die "NullPointerException" implizit zu verwenden. Die NullPointerException ist eine Ausnahme, die von der Java Virtual Machine ausgelöst wird, wenn Sie versuchen, Code für eine Nullreferenz auszuführen (Like toString () ).

Claude Houle
quelle
6

Das Auslösen einer Ausnahme, die ausschließlich für nullArgumente gilt (unabhängig davon, ob es sich um NullPointerExceptioneinen benutzerdefinierten Typ handelt), macht automatisierte nullTests zuverlässiger. Diese automatisierten Tests können mit Reflexion und eine Reihe von Standardwerten, wie in getan werden Guava ist NullPointerTester. Zum Beispiel NullPointerTesterwürde versuchen , das folgende Verfahren zu nennen ...

Foo(String string, List<?> list) {
  checkArgument(string.length() > 0);
  // missing null check for list!
  this.string = string;
  this.list = list;
}

... mit zwei Argumentlisten: "", nullund null, ImmutableList.of(). Es würde testen, ob jeder dieser Aufrufe den erwarteten Wert auslöst NullPointerException. Bei dieser Implementierung wird das Übergeben einer nullListe nicht erzeugt NullPointerException. Es wird jedoch zufällig eine erzeugt, IllegalArgumentExceptionweil NullPointerTesterzufällig eine Standardzeichenfolge von verwendet wird "". Wenn NullPointerTestererwartet nur NullPointerExceptionfür nullWerte, fängt sie den Fehler. Wenn es erwartet IllegalArgumentException, verfehlt es es.

Chris Povirk
quelle
5

Einige Sammlungen gehen davon aus, dass dies eher mit als nullabgelehnt wird . Wenn Sie beispielsweise einen Satz mit einem Satz vergleichen, der ablehnt , ruft der erste Satz den anderen auf und fängt dessen ab - aber nicht . (Ich schaue auf die Implementierung von .)NullPointerExceptionIllegalArgumentExceptionnullnullcontainsAllNullPointerExceptionIllegalArgumentExceptionAbstractSet.equals

Sie könnten vernünftigerweise argumentieren, dass die Verwendung von ungeprüften Ausnahmen auf diese Weise ein Antimuster ist, dass der Vergleich von Sammlungen, die enthalten, nullmit Sammlungen, die keine enthalten können, nullein wahrscheinlicher Fehler ist, der wirklich eine Ausnahme hervorrufen sollte , oder dass das Einfügen nulleiner Sammlung überhaupt eine schlechte Idee ist . Wenn Sie jedoch nicht bereit sind zu sagen, dass dies equalsin einem solchen Fall eine Ausnahme auslösen sollte, müssen Sie sich nicht daran erinnern, dass NullPointerExceptiondies unter bestimmten Umständen erforderlich ist, unter anderen jedoch nicht. ("IAE vor NPE außer nach 'c' ...")

Chris Povirk
quelle
Ich sehe nicht, wie das enthält eine NPE abhängig von einem Element in der Sammlung auslöst. Der einzige Grund, warum eine NPE ausgelöst wird (afaict), ist, dass die Sammlung selbst null ist (in diesem Fall wird die NPE ausgelöst, weil sie versucht, auf ihren Iterator zuzugreifen). Dies wirft jedoch die Frage auf, ob die Null-Eingabe überprüft werden soll oder ob sie sich bis zum Zugriff weitergeben soll.
Alowaniak
2
new TreeSet<>().containsAll(Arrays.asList((Object) null));wirft, NPEweil das Listenthält null.
Chris Povirk
1
In der Tat enthält TreeSet # Throws NPE "wenn das angegebene Element null ist und diese Menge eine natürliche Reihenfolge verwendet oder der Komparator keine Nullelemente zulässt". Ich habe mir nur AbstractSet angesehen, das null zulässt, mein schlechtes. Persönlich finde ich es seltsam, dass es nicht nur false zurückgibt, da in diesem Fall möglicherweise keine Null hinzugefügt werden kann.
Alowaniak
5

Als subjektive Frage sollte dies geschlossen werden, aber da es noch offen ist:

Dies ist Teil der internen Politik, die an meinem früheren Arbeitsplatz angewendet wurde, und hat sehr gut funktioniert. Dies ist alles aus dem Gedächtnis, so dass ich mich nicht an den genauen Wortlaut erinnern kann. Es ist erwähnenswert, dass sie keine geprüften Ausnahmen verwendet haben, aber das geht über den Rahmen der Frage hinaus. Die ungeprüften Ausnahmen, die sie verwendeten, fielen in drei Hauptkategorien.

NullPointerException: Nicht absichtlich werfen. NPEs dürfen nur von der VM ausgelöst werden, wenn eine Nullreferenz dereferenziert wird. Es sind alle möglichen Anstrengungen zu unternehmen, um sicherzustellen, dass diese niemals geworfen werden. @Nullable und @NotNull sollten in Verbindung mit Code-Analyse-Tools verwendet werden, um diese Fehler zu finden.

IllegalArgumentException: Wird ausgelöst, wenn ein Argument für eine Funktion nicht mit der öffentlichen Dokumentation übereinstimmt, sodass der Fehler anhand der übergebenen Argumente identifiziert und beschrieben werden kann. Die Situation des OP würde in diese Kategorie fallen.

IllegalStateException: Wird ausgelöst, wenn eine Funktion aufgerufen wird und ihre Argumente zum Zeitpunkt der Übergabe entweder unerwartet sind oder nicht mit dem Status des Objekts kompatibel sind, zu dem die Methode gehört.

Beispielsweise gab es zwei interne Versionen der IndexOutOfBoundsException, die in Dingen mit einer Länge verwendet wurden. Eine Unterklasse von IllegalStateException, die verwendet wird, wenn der Index größer als die Länge war. Die andere ist eine Unterklasse von IllegalArgumentException, die verwendet wird, wenn der Index negativ war. Dies lag daran, dass Sie dem Objekt weitere Elemente hinzufügen konnten und das Argument gültig war, während eine negative Zahl niemals gültig ist.

Wie gesagt, dieses System funktioniert wirklich gut, und es hat jemanden gebraucht, um zu erklären, warum der Unterschied besteht: "Abhängig von der Art des Fehlers ist es für Sie recht einfach, herauszufinden, was zu tun ist. Auch wenn Sie nicht wirklich herausfinden können Wenn Sie herausfinden, was schief gelaufen ist, können Sie herausfinden, wo Sie diesen Fehler abfangen und zusätzliche Debugging-Informationen erstellen können. "

NullPointerException: Behandeln Sie den Null-Fall oder geben Sie eine Zusicherung ein, damit die NPE nicht ausgelöst wird. Wenn Sie eine Behauptung aufstellen, ist dies nur einer der beiden anderen Typen. Wenn möglich, fahren Sie mit dem Debuggen fort, als ob die Behauptung überhaupt vorhanden wäre.

IllegalArgumentException: An Ihrer Anrufstelle stimmt etwas nicht. Wenn die übergebenen Werte von einer anderen Funktion stammen, finden Sie heraus, warum Sie einen falschen Wert erhalten. Wenn Sie eines Ihrer Argumente übergeben, überprüft der Fehler den Aufrufstapel, bis Sie die Funktion finden, die nicht das zurückgibt, was Sie erwarten.

IllegalStateException: Sie haben Ihre Funktionen nicht in der richtigen Reihenfolge aufgerufen. Wenn Sie eines Ihrer Argumente verwenden, überprüfen Sie diese und lösen Sie eine IllegalArgumentException aus, die das Problem beschreibt. Sie können dann die Wangen gegen den Stapel ausbreiten, bis Sie das Problem finden.

Sein Punkt war jedenfalls, dass Sie nur die IllegalArgumentAssertions auf den Stapel kopieren können. Es gibt keine Möglichkeit für Sie, die IllegalStateExceptions oder NullPointerExceptions im Stack weiterzugeben, da sie etwas mit Ihrer Funktion zu tun haben.

Ben Seidel
quelle
4

Im Allgemeinen sollte ein Entwickler niemals eine NullPointerException auslösen. Diese Ausnahme wird von der Laufzeit ausgelöst, wenn der Code versucht, eine Variable zu dereferenzieren, deren Wert null ist. Wenn Ihre Methode null explizit nicht zulassen möchte, anstatt zufällig einen Nullwert für eine NullPointerException auszulösen, sollten Sie daher eine IllegalArgumentException auslösen.


quelle
9
JavaDoc auf NPE hat eine andere Meinung: "Anwendungen sollten Instanzen dieser Klasse auslösen, um andere illegale Verwendungen des Null-Objekts anzuzeigen." Sei nicht so kategorisch
Donz
4

Ich wollte Null-Argumente von anderen illegalen Argumenten unterscheiden, daher habe ich eine Ausnahme von IAE mit dem Namen NullArgumentException abgeleitet. Ohne die Ausnahmemeldung lesen zu müssen, weiß ich, dass ein Nullargument an eine Methode übergeben wurde, und durch Lesen der Nachricht finde ich heraus, welches Argument Null war. Ich fange die NullArgumentException immer noch mit einem IAE-Handler ab, aber in meinen Protokollen kann ich den Unterschied schnell erkennen.

Jason Fritcher
quelle
Ich habe den Ansatz "Neue IllegalArgumentException (" foo == null ") werfen" übernommen. Sie müssen den Variablennamen trotzdem protokollieren (um sicherzugehen, dass Sie die richtige Anweisung usw. anzeigen)
Thorbjørn Ravn Andersen
4

die Dichotomie ... Überlappen sie sich nicht? Nur nicht überlappende Teile eines Ganzen können eine Zweiteilung vornehmen. Wie ich es sehe:

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));
Luis Daniel Mesa Velasquez
quelle
1
Dies würde den Overhead für die Erstellung von Ausnahmen verdoppeln und würde nicht wirklich helfen, da das Fangen NullPointerExceptionnichts bewirken würde. Das einzige, was helfen könnte, ist IllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException, aber wir haben keine Mehrfachvererbung.
Maaartinus
Ich glaube, dass spezifischere Ausnahmen von allgemeineren Ausnahmen umschlossen werden sollten. NPE steht für einen Ausdruck, IAE für eine Methode. Da Methoden Anweisungen enthalten, die Ausdrücke enthalten, ist IAE allgemeiner.
Sgene9
In Bezug auf den Overhead habe ich keine Ahnung. Aber da die Stacktraces grundsätzlich identisch wären, außer dass sich der Name der Ausnahme in der Mitte geändert hat, sollte es für doppelte Ausnahmen nicht zu viel Overhead geben. Wenn jemand über den Overhead besorgt ist, kann er "if" -Anweisungen verwenden, um eine Null oder -1 zurückzugeben, anstatt eine Ausnahme auszulösen.
Sgene9
4

NullPointerExceptionWird ausgelöst, wenn versucht wird, auf ein Objekt mit einer Referenzvariablen zuzugreifen, deren aktueller Wert lautet null.

IllegalArgumentException Wird ausgelöst, wenn eine Methode ein Argument empfängt, das anders formatiert ist als von der Methode erwartet.

Nitesh Soomani
quelle
3

Entsprechend Ihrem Szenario IllegalArgumentExceptionist dies die beste Wahl, da nulles sich nicht um einen gültigen Wert für Ihre Immobilie handelt.

Löwe
quelle
0

Im Idealfall sollten Laufzeitausnahmen nicht ausgelöst werden. Für Ihr Szenario sollte eine aktivierte Ausnahme (Geschäftsausnahme) erstellt werden. Wenn eine dieser Ausnahmen ausgelöst und protokolliert wird, führt dies den Entwickler beim Durchlaufen der Protokolle in die Irre. Stattdessen verursachen Geschäftsausnahmen keine Panik und werden normalerweise bei der Fehlerbehebung bei Protokollen ignoriert.

Vijay
quelle
-1

Die Definitionen aus den Links zu den beiden oben genannten Ausnahmen lauten IllegalArgumentException: Wird ausgelöst, um anzuzeigen, dass einer Methode ein unzulässiges oder unangemessenes Argument übergeben wurde. NullPointerException: Wird ausgelöst, wenn eine Anwendung versucht, null zu verwenden, wenn ein Objekt erforderlich ist.

Der große Unterschied besteht darin, dass die IllegalArgumentException verwendet werden soll, wenn überprüft wird, ob ein Argument für eine Methode gültig ist. NullPointerException soll immer dann verwendet werden, wenn ein Objekt "verwendet" wird, wenn es null ist.

Ich hoffe, das hilft, die beiden in die richtige Perspektive zu rücken.

Martinatime
quelle
1
Das herausragende Bit ist, dass es die Anwendung ist, die null verwendet, nicht die Laufzeit. Es gibt also eine ziemlich große Überschneidung zwischen "wenn einer Methode ein illegales oder unangemessenes Argument übergeben wurde" und "wenn eine Anwendung null verwendet". Wenn eine App eine Null für ein Feld übergibt, für das keine Null erforderlich ist, werden theoretisch beide Kriterien erfüllt.
Christopher Smith
-1

Wenn es sich um einen "Setter" handelt oder wenn ich ein Mitglied später zur Verwendung bringe, verwende ich normalerweise IllegalArgumentException.

Wenn es etwas ist, das ich gerade in der Methode verwenden werde (Dereferenzierung), löse ich proaktiv eine NullPointerException. Ich mag das besser, als die Laufzeit es tun zu lassen, weil ich eine hilfreiche Nachricht liefern kann (anscheinend könnte die Laufzeit dies auch tun, aber das ist ein Scherz für einen anderen Tag).

Wenn ich eine Methode überschreibe, verwende ich alles, was die überschriebene Methode verwendet.

erickson
quelle
-1

Sie sollten eine IllegalArgumentException auslösen, da dies dem Programmierer klar macht, dass er etwas Ungültiges getan hat. Entwickler sind es so gewohnt, dass NPE von der VM ausgelöst wird, dass jeder Programmierer seinen Fehler nicht sofort erkennt und sich zufällig umschaut oder, schlimmer noch, Ihren Code für "fehlerhaft" verantwortlich macht.

Will Sargent
quelle
4
Entschuldigung, wenn sich ein Programmierer "zufällig" umschaut, wenn er eine Ausnahme erhält ... das Ändern des Namens einer Ausnahme hilft nicht viel.
Christopher Smith
-1

In diesem Fall übermittelt IllegalArgumentException dem Benutzer mithilfe Ihrer API eindeutige Informationen, dass "nicht null sein sollte". Wie andere Forumbenutzer betonten, können Sie NPE verwenden, wenn Sie möchten, solange Sie dem Benutzer mithilfe Ihrer API die richtigen Informationen übermitteln.

GaryF und tweakt haben "Effective Java" -Referenzen (auf die ich schwöre) verworfen, die die Verwendung von NPE empfehlen. Wenn Sie sich ansehen, wie andere gute APIs erstellt werden, können Sie am besten sehen, wie Sie Ihre API erstellen.

Ein weiteres gutes Beispiel sind die Spring-APIs. Beispielsweise hat org.springframework.beans.BeanUtils.instantiateClass (Konstruktor ctor, Object [] args) eine Assert.notNull-Zeile (ctor, "Konstruktor darf nicht null sein"). Die Methode org.springframework.util.Assert.notNull (Objektobjekt, String-Nachricht) prüft, ob das übergebene Argument (Objekt) null ist und ob es eine neue IllegalArgumentException (Nachricht) auslöst, die dann in der Organisation abgefangen wird. springframework.beans.BeanUtils.instantiateClass (...) -Methode.


quelle
-5

Wenn Sie eine NPE auslösen und das Argument in Ihrer Methode verwenden, ist es möglicherweise redundant und teuer, explizit nach einer Null zu suchen. Ich denke, die VM erledigt das bereits für Sie.

jassuncao
quelle
Die Laufzeit enthält keine aussagekräftige Nachricht.
mP.
Eigentlich könnte dieser Kommentar eine andere Meinung ableiten. Lassen Sie die VM sprechen, NPEaber die Programmierer sprechen IAEvor der VM, wenn sie möchten.
Jin Kwon
1
Teuer? Ich denke nicht, dass == null so teuer ist ... Außerdem kann das Argument null nur für die letztere Verwendung gespeichert werden und löst lange nach dem Methodenaufruf eine Ausnahme aus, wodurch der Fehler schwieriger zu verfolgen ist. Oder Sie können ein teures Objekt erstellen, bevor Sie das Argument null verwenden, und so weiter. Früherkennung scheint eine gute Option zu sein.
PhiLho
Das Abstimmen dieser Antwort ist ein Missverständnis der dahinter stehenden Hardware. Sicherlich sind die Hardwareprüfungen (die die CPU durchführt) billiger als die explizite Prüfung. Das Dereferenzieren von Null ist ein SegmentationFault (SegV) -Spezialfall (Zugriff auf eine Seite, die nicht dem Prozess gehört), den die CPU / das Betriebssystem überprüft und JRE als Sonderfall behandelt, der eine NullPointerException auslöst.
digital_infinity