576 Stimmen

IllegalArgumentException oder NullPointerException für einen Null-Parameter?

Ich habe eine einfache Setter-Methode für eine Eigenschaft und null ist für diese spezielle Immobilie nicht geeignet. Ich war in dieser Situation immer hin- und hergerissen: Sollte ich eine IllegalArgumentException oder eine NullPointerException ? Nach den Javadocs scheinen beide geeignet zu sein. Gibt es so etwas wie einen anerkannten Standard? Oder ist das einfach so, dass man das tun sollte, was man bevorzugt, und beides ist wirklich richtig?

8voto

Sascha Baumeister Punkte 332

Die Frage, ob eine IllegalArgumentException oder eine NullPointerException geworfen werden soll, ist meiner bescheidenen Meinung 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 zwar wie folgt:

  • Verletzungen von Argumenten müssen so schnell wie möglich angezeigt werden (-> Fast Fail), um illegale Zustände zu vermeiden, die viel schwieriger zu beheben sind
  • im Falle eines ungültigen Null-Zeigers, aus welchem Grund auch immer, NullPointerException auslösen
  • im Falle eines unzulässigen Array-/Sammlungsindex, ArrayIndexOutOfBounds auslösen
  • im Falle einer negativen Array-/Sammlungsgröße, NegativeArraySizeException auslösen
  • im Falle eines unzulässigen Arguments, das nicht unter die oben genannten Ausnahmen fällt und für das es keinen anderen, spezifischeren Ausnahmetyp gibt, IllegalArgumentException als Papierkorb werfen
  • andererseits im Falle einer Einschränkungsverletzung IN EINEM FELD, die aus irgendeinem triftigen Grund nicht durch Fast Fail 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, etc. passieren!

Es gibt mindestens drei sehr gute Gründe, die dagegen sprechen, alle Arten von Verletzungen von Argumenteinschränkungen auf IllegalArgumentException abzubilden, wobei der dritte wahrscheinlich so schwerwiegend ist, dass er die Praxis als schlechten Stil bezeichnet:

(1) Ein Programmierer kann nicht sicher davon ausgehen, dass alle Fälle von Verletzungen von Argumenteinschränkungen zu IllegalArgumentException führen, da die große Mehrheit der Standardklassen diese Ausnahme eher als Papierkorb verwenden, wenn keine spezifischere Art von Ausnahme verfügbar ist. Der Versuch, alle Fälle von Verletzungen von Argumenteneinschränkungen in Ihrer API auf IllegalArgumentException abzubilden, führt nur zu einer Frustration der Programmierer bei der Verwendung Ihrer Klassen, da die Standardbibliotheken meist anderen Regeln folgen, die gegen die Ihren verstoßen, und die meisten Ihrer API-Benutzer werden diese ebenfalls verwenden!

(2) Das Mapping der Ausnahmen führt zu einer anderen Art von Anomalie, die durch die Einfachvererbung verursacht wird: Alle Java-Ausnahmen sind Klassen und unterstützen daher nur Einfachvererbung. Daher gibt es keine Möglichkeit, eine Ausnahme zu erstellen, die wirklich sowohl eine NullPointerException als auch eine IllegalArgumentException ist, da Unterklassen nur von einer der beiden Ausnahmen erben können. Das Auslösen einer IllegalArgumentException im Falle eines Null-Arguments macht es daher für API-Benutzer schwieriger, zwischen Problemen zu unterscheiden, wenn ein Programm versucht, das Problem programmatisch zu korrigieren, indem es beispielsweise Standardwerte in eine Aufrufwiederholung einspeist!

(3) Das Mapping birgt die Gefahr der Fehlerverdeckung in sich: Um Verletzungen von Argumenteinschränkungen in IllegalArgumentException abzubilden, müssen Sie in jeder Methode, die eingeschränkte Argumente hat, ein äußeres try-catch codieren. Das einfache Abfangen von RuntimeException in diesem Catch-Block kommt jedoch nicht in Frage, da dies das Risiko birgt, dass dokumentierte RuntimeExceptions, die von libery-Methoden ausgelöst werden, die in Ihrer Methode verwendet werden, in IllegalArgumentException abgebildet werden, selbst wenn sie nicht durch Verletzungen von Argumenten 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 RuntimeException einer anderen API (d.h. einen Fehler) in eine IllegalArgumentException Ihrer API mappen. Selbst das sorgfältigste Mapping birgt daher die Gefahr, dass Programmierfehler anderer Bibliothekshersteller als Verletzungen von Argumenteinschränkungen der Benutzer Ihrer Methode maskiert werden, was schlichtweg ungesetzlich ist!

Bei der Standardpraxis hingegen bleiben die Regeln einfach, und die Ausnahmeursachen bleiben unmaskiert und spezifisch. Auch für den Methodenaufrufer sind die Regeln einfach: - Wenn Sie auf eine dokumentierte Laufzeitausnahme irgendeiner Art stoßen, weil Sie einen unzulässigen Wert übergeben haben, wiederholen Sie entweder den Aufruf mit einem Standardwert (hierfür sind spezifische Ausnahmen erforderlich) oder korrigieren Sie Ihren Code - Wenn Sie hingegen eine Laufzeitausnahme feststellen, die für einen bestimmten Satz von Argumenten nicht dokumentiert ist, reichen Sie einen Fehlerbericht bei den Machern der Methode ein, um sicherzustellen, dass entweder ihr Code oder ihre Dokumentation korrigiert wird.

7voto

Allain Lalonde Punkte 88365

Ich kann dem, was hier gesagt wird, nur zustimmen. Früh scheitern, schnell scheitern. Ein ziemlich gutes Mantra für Ausnahmen.

Die Frage, welche Ausnahme man werfen soll, ist vor allem eine Frage des persönlichen Geschmacks. Meiner Meinung nach ist IllegalArgumentException spezifischer als eine NPE, da sie mir mitteilt, dass das Problem mit einem Argument zusammenhängt, das ich an die Methode übergeben habe, und nicht mit einem Wert, der bei der Ausführung der Methode erzeugt wurde.

Meine 2 Cents

6voto

Chris Povirk Punkte 3542

Das Auslösen einer Ausnahme, die ausschließlich für null Argumente (ob NullPointerException oder einen benutzerdefinierten Typ) macht automatisierte null zuverlässiger zu testen. Diese automatisierten Tests können mit Reflexion und einer Reihe von Standardwerten durchgeführt werden, wie in Guave 's NullPointerTester . Zum Beispiel, NullPointerTester würde versuchen, die folgende Methode aufzurufen...

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

...mit zwei Listen von Argumenten: "", null y null, ImmutableList.of() . Es würde testen, ob jeder dieser Aufrufe die erwartete Reaktion auslöst. NullPointerException . Bei dieser Implementierung ist die Übergabe einer null Liste tut pas produzieren NullPointerException . Sie erzeugt jedoch zufällig eine IllegalArgumentException denn NullPointerTester verwendet zufällig eine Standardzeichenfolge von "" . Si NullPointerTester erwartet nur NullPointerException para null Werte, fängt es den Fehler auf. Wenn er erwartet IllegalArgumentException verfehlt er sie.

6voto

Claude Houle Punkte 38165

Die gängige Praxis ist die Verwendung der IllegalArgumentException( String message ) um einen Parameter als ungültig zu erklären und so viele Details wie möglich anzugeben... Um also zu sagen, dass ein Parameter als ungültig erkannt wurde, obwohl die Ausnahme nicht ungültig ist, würden Sie etwas wie folgt tun:

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 mit einer Null-Referenz auszuführen (wie toString() ).

5voto

Chris Povirk Punkte 3542

Einige Sammlungen gehen davon aus, dass null wird zurückgewiesen durch NullPointerException statt IllegalArgumentException . Wenn Sie zum Beispiel ein Set vergleichen, das null zu einer Menge, die ablehnt null ruft der erste Satz containsAll auf der anderen Seite und fangen seine NullPointerException -- aber nicht IllegalArgumentException . (Ich betrachte die Implementierung von AbstractSet.equals .)

Man könnte vernünftigerweise argumentieren, dass die Verwendung ungeprüfter Ausnahmen auf diese Weise ein Antipattern ist, dass der Vergleich von Sammlungen, die null zu Sammlungen, die nicht enthalten können null ist wahrscheinlich ein Fehler, der wirklich debe zu einer Ausnahme führen, oder dass die null in einer Sammlung überhaupt eine schlechte Idee ist. Dennoch, wenn Sie nicht bereit sind zu sagen, dass equals in einem solchen Fall eine Ausnahme auslösen sollte, müssen Sie sich daran erinnern, dass NullPointerException ist unter bestimmten Umständen erforderlich, unter anderen nicht. ("IAE vor NPE außer nach 'c'...")

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X