Betrachten Sie eine Funktion der folgenden allgemeinen Form:
Foo findFoo(Collection<Foo> foos, otherarguments)
throws ObjectNotFoundException {
for(Foo foo : foos){
if(/* foo meets some condition*/){
return foo;
}
}
throw new ObjectNotFoundException();
}
Ein konkreter Fall wäre zum Beispiel:
User findUserByName(Collection<User> users, String name)
throws ObjectNotFoundException {
for(User user : users){
if(user.getName().equals(name)){
return user;
}
}
throw new ObjectNotFoundException();
}
Diese Funktionen lösen eine Ausnahme aus, wenn das Objekt nicht gefunden wird. Ich kann zu diesem Zweck eine benutzerdefinierte Ausnahmeklasse erstellen (in den Beispielen ObjectNotFoundException
), würde jedoch lieber eine vorhandene Klasse verwenden. In der Standard-Java-Bibliothek konnte ich jedoch keine Ausnahmeklasse mit dieser Bedeutung finden. Wissen Sie, ob es eine Standardausnahme gibt, die hier verwendet werden kann?
IlleagalArgumentException
?IllegalArgumentException
wie die Dokumentation sagt:Thrown to indicate that a method has been passed an illegal or inappropriate argument.
Was ist in der Tat, was passiert.NoSuchElementException
Antworten:
Es gibt einige Ausnahmen, die verwendet werden könnten (z. B.
NoSuchElementException
oderIllegalArgumentException
), aber die Antwort hängt wirklich von der Semantik ab, die Sie vermitteln möchten:NoSuchElementException
Wird normalerweise verwendet, wenn Sie eine Sequenz oder Aufzählung durchlaufen, wobei Sie hier eine Suche haben.IllegalArgumentException
Dies deutet darauf hin, dass das Argument fehlerhaft ist. In diesem Fall kann es jedoch sein, dass die Annahmen des Aufrufers falsch sind oder spezifisch für die Anwendungslogik sind.Mit einer benutzerdefinierten Ausnahme können Sie (in den Javadocs) genau angeben, was die Ausnahme bedeutet. Sie können auch deklarieren, dass es überprüft werden soll ... falls dies angemessen ist.
(Aber seien Sie nicht versucht zu benutzen
UnknownUserException
. Das wäre schrecklich falsch; lesen Sie den Javadoc!)Es lohnt sich auch, eine Rückgabe in Betracht zu ziehen
null
, insbesondere wenn ein Suchfehler wahrscheinlich ein ziemlich häufiges (nicht außergewöhnliches) Ereignis in Ihrer Anwendung ist. Der Nachteil der Rückgabenull
ist jedoch, dass der Anrufer nachnull
unerwartetenNullPointerException
s suchen oder diese riskieren muss . In der Tat würde ich argumentieren, dass Überbeanspruchungnull
schlimmer ist als Überbeanspruchung von Ausnahmen. Ersteres kann zu unzuverlässigen Anwendungen führen, während letzteres "nur" die Leistung beeinträchtigt.Für Java 8 und höher
Optional
wäre die Rückgabe von a eine sauberere Wahl als die Rückgabe von anull
.In diesen Dingen ist es wichtig, über die Dogmen hinauszuschauen und sich anhand der tatsächlichen Kontextbedingungen zu entscheiden.
quelle
Ausnahmen werden erstellt, um außergewöhnliches Verhalten zu kennzeichnen. Meiner Meinung nach ist eine nicht gefundene Objektsituation keine Ausnahme. Ich würde Ihre Methode so umschreiben, dass sie null zurückgibt, wenn der Benutzer nicht gefunden wird.
User findUserByName(Collection<User> users, String name) { for(User user : users){ if(user.getName().equals(name)){ return user; } } return null; }
Dies ist das Standardverhalten vieler Java-Sammlungen. Beispielsweise gibt http://docs.oracle.com/javase/7/docs/api/java/util/Map.html#get(java.lang.Object) null zurück, wenn sich kein Eintrag mit dem angegebenen Schlüssel in der befindet Karte.
Sie sollten vermeiden, sich auf Ausnahmen in Ihrer Programmlogik zu verlassen.
quelle
null
ist böse - wenn Sie Java 8 verwenden können, sollten Sie verwenden,Optional
wenn die Methode das angeforderte Objekt (daher den Namen) möglicherweise nicht zurückgibt. Ansonsten kommt es darauf an. Ich ziehe es vor, Ausnahmen in öffentliche Methoden zu werfen undnull
privat zurückzukehren.IllegalArgumentException
wird hier manchmal verwendet, aber die Verwendung Ihrer eigenen Ausnahme ist vollkommen in Ordnung.Nebenbei würde ich empfehlen, eine Karte mit
String name
als Schlüssel undUser
als Wert zu verwenden. Ein Iterieren über die Sammlung wäre dann unnötig und würde verhindern, dass zwei Benutzer mit demselben Namen in der Sammlung sind. Wenn Sie keine Karte verwenden möchten, verteidigen Sie sich zumindestNullPointerException
wie folgt:User findUserByName(Collection<User> users, String name) throws ObjectNotFoundException { if (name == null) { throw new IllegalArgumentException("name parameter must not be null"); } if (users == null) { throw new IllegalArgumentException("Collection of users must not be null"); } for(User user : users) { if(name.equals(user.getName())) { return user; } } throw new ObjectNotFoundException("Unable to locate user with name: " + name); }
quelle
null
und NPEs "verteidigen" sollten. Die alternative Sichtweise ist , dass , wenn einnull
an eine API - Methode übergeben wird , das nicht dokumentiert , wie erlaubtnull
, dann ist das ein Fehler ist, und Sie sollten die NPE (als die spezifischen Ausnahme für diese Bedingung) werfen. Das vollständige Verhindern der NPE (z. B. durch den Versuch, "Gutes zu tun") oder das Auslösen einer anderen Ausnahme hilft nicht weiter und kann die Situation verschlimmern, indem ein Problem ausgeblendet wird, das dem Entwickler / Betreuer zur Kenntnis gebracht werden sollte.NullPointerException
oder ein werfenIllegalArgumentException
. Beide sind nicht aktivierte Ausnahmen, und beide sollten dazu führen, dass der Aufrufer mit einem Stacktrace "aussteigt", den der Entwickler einsehen kann. Zumindest ist dieusers == null
Prüfung also redundant. (NPE ist dein Freund, nicht dein Feind!)Mit Java 8 würde ich empfehlen, für diesen Anwendungsfall eine Option zu verwenden.
Optional<User> findUserByName(Collection<User> users, String name){ Optional<User> value = users .stream() .filter(a -> a.equals(name)) .findFirst(); }
Dies macht dem Anrufer auch sehr deutlich, dass das Optionale leer sein kann, wenn der Wert nicht gefunden wird. Wenn Sie wirklich eine Ausnahme auslösen möchten, können Sie sie
orElseThrows
in Optional verwenden, um sie zu erreichen.quelle
Dies hängt vom dokumentierten Schnittstellenvertrag Ihrer Methode ab:
Wenn in der Dokumentation Ihrer Methode angegeben ist, dass das
name
Argument dem Namen eines vorhandenen Benutzers entsprechen muss , ist es angebracht, zu werfen,IllegalArgumentException
wenn der Name nicht gefunden wird, da dies bedeutet, dass der Aufrufer die Anforderungen der Methode verletzt hat, indem er einen Namen übergeben hat, der nicht entspricht Ein Benutzer.Wenn Ihre Methode nicht sagt, dass der Name einem vorhandenen Benutzer entsprechen muss, ist die Übergabe eines unbekannten Namens kein Fehler und Sie sollten überhaupt keine Ausnahme auslösen. Eine Rückgabe
null
wäre in dieser Situation angebracht.Beachten Sie, dass Ihre
findUserByName
Methode die Methode im Grunde neu erfindet, die zurückgegebenMap.get
wird,null
wenn der angegebene Schlüssel nicht gefunden wird.quelle