Gibt es eine Standard-Java-Ausnahmeklasse, die bedeutet, dass das Objekt nicht gefunden wurde?

76

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?

abl
quelle
IlleagalArgumentException ?
Suresh Atta
Und warum bestehen Sie darauf, dass das JDK die Ausnahme bereitstellt, wenn es drei Codezeilen umfasst, um es selbst bereitzustellen? Ich weiß nicht, mit welchen APIs Sie zusätzlich arbeiten. JPA bietet beispielsweise eine "NoResultException".
Gimby
Ich würde gehen für: IllegalArgumentExceptionwie die Dokumentation sagt: Thrown to indicate that a method has been passed an illegal or inappropriate argument.Was ist in der Tat, was passiert.
Jorge Campos
4
IMHO Es ist besser, eine benutzerdefinierte Ausnahme zu erstellen, die für den Kontext Ihrer Methode / Klasse / Ebene / Anwendung relevant ist, aber wenn Sie darauf bestehen, können Sie verwendenNoSuchElementException
Svetlin Zarev
7
@ Gimby Zu welchem ​​Zeitpunkt "bestand" OP darauf, dass das JDK die Ausnahme bereitstellt? OP gab eine Präferenz an und stellte eine Frage. Darüber hinaus werden drei Codezeilen bei entsprechender Dokumentation länger. Und warum sich die Mühe machen, wenn das JDK es bereits bereitstellt?
Broschüre

Antworten:

89

Wissen Sie, ob es eine Standardausnahme gibt, die hier verwendet werden kann?

Es gibt einige Ausnahmen, die verwendet werden könnten (z. B. NoSuchElementExceptionoder IllegalArgumentException), 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ückgabe nullist jedoch, dass der Anrufer nach nullunerwarteten NullPointerExceptions suchen oder diese riskieren muss . In der Tat würde ich argumentieren, dass Überbeanspruchung nullschlimmer 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 Optionalwäre die Rückgabe von a eine sauberere Wahl als die Rückgabe von a null.


In diesen Dingen ist es wichtig, über die Dogmen hinauszuschauen und sich anhand der tatsächlichen Kontextbedingungen zu entscheiden.

Stephen C.
quelle
7

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.

MGorgon
quelle
18
Woher weißt du, dass es keine Ausnahme ist? Das hängt von der Anwendung ab! Entschuldigung, aber es gibt keine Möglichkeit (abgesehen von der zirkulären Logik) zu begründen, dass ein vermisster Benutzer niemals eine Ausnahmesituation ist.
Stephen C
7
nullist böse - wenn Sie Java 8 verwenden können, sollten Sie verwenden, Optionalwenn 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 und nullprivat zurückzukehren.
Svetlin Zarev
1
@StephenC, Sie meinen "das hängt von der Anwendungslogik ab" - wie ich zuvor geschrieben habe, wird das Erstellen von Anwendungslogik unter Verwendung von Ausnahmen als Antimuster betrachtet. Lesen Sie hier mehr: programmers.stackexchange.com/questions/189222/…
MGorgon
6
IMO, ob die Situation außergewöhnlich ist oder nicht, hängt vom Code ab, der die Methode aufruft. Wenn die übergebene Sammlung so erstellt wurde, dass sie das Element enthalten sollte , verdient die Tatsache, dass das Objekt nicht vorhanden ist, eine Ausnahme.
Abl
2
@MGorgon - Jetzt greifen Sie auf zirkuläre Logik zurück. Das Dogma "Ausnahmen sollten nicht für die Anwendungslogik verwendet werden" geht davon aus, dass eine klare Unterscheidung zwischen Anwendungslogik und dem Umgang mit außergewöhnlichen Ereignissen besteht. Es gibt keine so klare Unterscheidung. Es ist eine Frage des Urteils / der Meinung.
Stephen C
4

IllegalArgumentException wird hier manchmal verwendet, aber die Verwendung Ihrer eigenen Ausnahme ist vollkommen in Ordnung.

Nebenbei würde ich empfehlen, eine Karte mit String nameals Schlüssel und Userals 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 zumindest NullPointerExceptionwie 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);
}
Paul
quelle
Später Kommentar. Es ist fraglich, ob Sie sich gegen nullund NPEs "verteidigen" sollten. Die alternative Sichtweise ist , dass , wenn ein nullan eine API - Methode übergeben wird , das nicht dokumentiert , wie erlaubt null, 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.
Stephen C
In diesem Beispiel macht es keinen Unterschied, ob Sie ein NullPointerExceptionoder ein werfen IllegalArgumentException. 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 die users == nullPrüfung also redundant. (NPE ist dein Freund, nicht dein Feind!)
Stephen C
4

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 orElseThrowsin Optional verwenden, um sie zu erreichen.

Alastor Moody
quelle
3

Dies hängt vom dokumentierten Schnittstellenvertrag Ihrer Methode ab:

Wenn in der Dokumentation Ihrer Methode angegeben ist, dass das nameArgument dem Namen eines vorhandenen Benutzers entsprechen muss , ist es angebracht, zu werfen, IllegalArgumentExceptionwenn 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 nullwäre in dieser Situation angebracht.

Beachten Sie, dass Ihre findUserByNameMethode die Methode im Grunde neu erfindet, die zurückgegeben Map.getwird, nullwenn der angegebene Schlüssel nicht gefunden wird.

Wyzard
quelle