web-dev-qa-db-fra.com

Existe-t-il une classe d'exception Java standard qui signifie "L'objet n'a pas été trouvé")?

Considérons une fonction de la forme générale suivante:

Foo findFoo(Collection<Foo> foos, otherarguments)
throws ObjectNotFoundException {
    for(Foo foo : foos){
        if(/* foo meets some condition*/){
            return foo;
        }
    }
    throw new ObjectNotFoundException();
}

Un cas concret, par exemple, serait:

User findUserByName(Collection<User> users, String name)
throws ObjectNotFoundException {
    for(User user : users){
        if(user.getName().equals(name)){
            return user;
        }
    }
    throw new ObjectNotFoundException();
}

Ces fonctions lèvent une exception si l'objet n'est pas trouvé. Je peux créer une classe d'exception personnalisée à cette fin (dans les exemples, ObjectNotFoundException) mais je préférerais utiliser une classe existante. Cependant, je n'ai trouvé aucune classe d'exception ayant cette signification dans la bibliothèque standard Java. Savez-vous s'il existe une exception standard pouvant être utilisée ici?

51
abl

Savez-vous s'il existe une exception standard pouvant être utilisée ici?

Il y a quelques exceptions qui pourraient être utilisées (par exemple, NoSuchElementException ou IllegalArgumentException), mais la réponse dépend vraiment de la sémantique que vous souhaitez transmettre:

  • NoSuchElementException a tendance à être utilisé lorsque vous parcourez une séquence ou une énumération, où ce que vous avez ici est une recherche.

  • IllegalArgumentException implique généralement que l'argument est une erreur, mais dans ce cas, les hypothèses de l'appelant pourraient être incorrectes, ou quelque chose de spécifique à la logique de l'application.

  • Une exception personnalisée vous permet de dire (dans les javadocs) exactement ce que signifie l’exception. Vous pouvez également le déclarer vérifié ... si cela convient.

(Mais ne soyez pas tenté d'utiliser UnknownUserException . Ce serait terriblement faux; lisez le javadoc!)


Il est également utile d'envisager de renvoyer null, surtout si l'échec de la recherche est susceptible d'être un événement assez commun (non exceptionnel) dans votre application. Cependant , l’inconvénient de renvoyer null est que l’appelant doit rechercher null ou risquer de ne pas être inattendu NullPointerExceptions. En fait, je dirais que la surutilisation de null est pire que la surutilisation d’exceptions. Les premières peuvent donner lieu à des applications non fiables, tandis que les dernières ne sont "que" mauvaises pour la performance.

Pour Java 8 et versions ultérieures, renvoyer un Optional serait un choix plus judicieux que de renvoyer un null.


Dans ces cas-là, il est important de regarder au-delà des dogmes et de se décider en fonction du contexte actuel.

61
Stephen C

Des exceptions sont créées pour marquer un comportement exceptionnel. À mon avis, la situation d'objet non trouvé n'est pas exceptionnelle. Je voudrais réécrire votre méthode pour renvoyer null, si l'utilisateur n'est pas trouvé.

User findUserByName(Collection<User> users, String name) {
   for(User user : users){
       if(user.getName().equals(name)){
           return user;
      }
    }
  return null; 
}

Ceci est un comportement standard pour de nombreuses Java Collections. Par exemple, http://docs.Oracle.com/javase/7/docs/api/Java/util/Map.html #get (Java.lang.Object) renverra la valeur null si aucune entrée avec la clé spécifiée ne figure dans la carte.

Vous devriez éviter de vous fier aux exceptions dans la logique de votre programme.

6
MGorgon

IllegalArgumentException est parfois utilisé ici, mais utiliser votre propre Exception convient parfaitement.

En passant, je vous recommande d'utiliser une carte avec String name comme clé et User comme valeur. Itérer sur la collection serait alors inutile et éviterait d'avoir deux utilisateurs portant le même nom dans la collection. Si vous ne voulez pas utiliser une carte, défendez-vous au moins contre NullPointerException comme ceci:

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);
}
4
Paul

Avec Java 8, je recommanderais l’utilisation d’un facultatif pour ce cas d’utilisation.

Optional<User> findUserByName(Collection<User> users, String name){
    Optional<User> value = users
        .stream()
        .filter(a -> a.equals(name))
        .findFirst();
}

Cela indique également très clairement à l'appelant que les options peuvent être vides si la valeur n'est pas trouvée. Si vous voulez vraiment lancer une exception, vous pouvez utiliser orElseThrows dans Optional pour le réaliser.

3
Alastor Moody

Cela dépend du contrat d'interface documenté de votre méthode:

Si la documentation de votre méthode indique que l'argument name doit correspondre au nom d'un utilisateur existant, il convient alors de lancer IllegalArgumentException si le nom n'est pas trouvé, car cela signifie que l'appelant a violé les exigences de la méthode en transmettant un nom qui ne correspond pas à un utilisateur.

Si votre méthode ne dit pas que le nom doit correspondre à un utilisateur existant, transmettre un nom inconnu ne constitue pas une erreur et vous ne devriez pas déclencher une exception du tout. Retourner null serait approprié dans cette situation.

Notez que votre méthode findUserByName réinvente le Map.get méthode, qui retourne null si la clé spécifiée n’est pas trouvée.

3
Wyzard