(Obwohl ich das eigentlich als “unöflich” empfinde, meine so genannten “Two cents”, obwohl ich nicht alle anderen Antworten komplett gelesen habe: )
- Die geeignetste Lösung hängt vom Anwendungsfall ab. (Schwurbel…).
Es ist ein gewaltiger Unterschied zwischen einer public
-Methode in einer public
-Klasse/Interface, und einer private
-Methode. Bei letzterer kann man mit solchen expliziten Tests deutlich sparsamer sein, weil man (bis zu einem gewissen Grad) davon ausgehen können muss, dass derjenige, der die Methode aufruft, weiß, was er dort tut. Eine public
-Methode sollte im Idealfall immer die Vorbedingungen rigoros testen, im Sinne von Preconditions, wie sie ThreadPool schon angesprochen hat. (Es gibt wenigSTe Ausnahmen dafür, z.B. wenn Performance wirklich höchst kritisch und der Test vergleichsweise “aufwändig” ist).
- Dokumentation!!!1111einselfelf
Die Vorbedingungen, die erfüllt sein müssen, sollten in der JavaDoc der Methode erwähnt werden. Auch oder sogar gerade, wenn sie NICHT explizit überprüft werden - d.h. auch oder sogar gerade bei private
methods.
/**
* Does something with the IDs...
*
* @param ids The IDs
* @throws IllegalArgumentException If the given list is <code>null</code>
* or the list is empty
*/
public void myfunc(List<ID> ids) {
if (ids == null) {
throw new IllegalArgumentException("ids are null");
}
if (ids.isEmpty()) {
throw new IllegalArgumentException("ids are empty");
}
process(ids);
}
/**
* Does something with the first ID. This method assumes
* that the given list is not <code>null</code> and contains
* at least one element.
*
* @param ids The IDs
*/
private void process(List<ID> ids) {
ID id = ids.get(0);
whatever(id);
}
- Man sollte sich überlegen, ob man “fail fast” will.
Es wurde erwähnt, dass z.B. eine NullPointerException eben fliegt wenn sie fliegt, und man das !=null
deswegen nicht als Vorbedingung prüfen muss. Einerseits stimmt das zwar, aber in vielen Fällen ist es besser, diese Prüfung dort zu machen, wo der Fehler herkommt, statt auf den Stack trace zu vertrauen, der einem nur sagt, wo der Fehler auftritt.
Im speziellen: Wenn man einen setter aufruft, und an anderer Stelle davon ausgeht, dass das Objekt, das dort gesetzt wurde, nicht null
ist, bringt einem die NullPointerException gerade mal gar nichts.
private Object object = defaultObject;
/** ... Object may never be null ... */
void setObject(Object object) {
this.object = object;
}
void methodThatIsCalledFromSomewhere() {
// Kein null-check...
object.doSomething();
}
Dort fliegt zwar ggf. die NullPointerException, aber “welcher Id!ot” die setObject
mit einem falschen Argument aufgerufen hat, erkennt man daran nicht.
Etwas allgemeiner: Man sollte sich immer peinlichst genau über den Zustandsraum seines Objektes im Klaren sein. Das heißt, dass man es bei allen Methoden, die den Zustandsraum direkt verändern (speziell bei settern oder Konstruktoren) mit den Prüfungen vielleicht etwas genauer nehmen sollte…
Für die Gewissenhaften
[spoiler]
Ich weiß tatsächlich von Projekten in “relativ professionellem (?)” Umfeld, wo große (!) Codeblöcke in
...
} catch (NullPointerException e) {}
eingewickelt wurden. Da läuft es einem echt mit 50Hz kalt den Rücken rauf und runter… :verzweifel:
[/spoiler]