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?
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 NullPointerException
s. 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.
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.
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);
}
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.
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.