À mon avis, il existe une différence entre renvoyer NULL, renvoyer un résultat vide (par exemple, la chaîne vide ou une liste vide) et renvoyer une exception.
Je prends normalement l'approche suivante. Je considère un appel de fonction ou de méthode f (v1, ..., vn) comme l'application d'une fonction
f : S x T1 x ... x Tn -> T
où S c'est "l'état du monde" T1, ..., Tn sont les types de paramètres d'entrée et T est le type de retour.
J'essaie d'abord de définir cette fonction. Si la fonction est partielle (c'est-à-dire qu'il y a des valeurs d'entrée pour lesquelles elle n'est pas définie), je retourne NULL pour le signaler. C'est parce que je veux que le calcul se termine normalement et me dire que la fonction que j'ai demandée n'est pas définie sur les entrées données. Utiliser, par exemple, une chaîne vide comme valeur de retour est ambigu, car il se peut que la fonction soit définie sur les entrées et que la chaîne vide corresponde au résultat correct.
Je pense que la vérification supplémentaire pour un pointeur NULL dans le code appelant est nécessaire parce que vous appliquez une fonction partielle et que la tâche de la méthode appelée vous indique si la fonction n'est pas définie pour l'entrée donnée.
Je préfère utiliser des exceptions pour les erreurs qui ne permettent pas d’effectuer le calcul (c’est-à-dire qu’il n’était pas possible de trouver une réponse).
Par exemple, supposons que j'ai une classe Client et que je souhaite implémenter une méthode.
Customer findCustomer(String customerCode)
pour rechercher un client dans la base de données d'application par son code. Dans cette méthode, je voudrais
- Retourne un objet de la classe Customer si la requête aboutit,
- Renvoie null si la requête ne trouve aucun client.
- Lancer une exception s'il n'est pas possible de se connecter à la base de données.
Les vérifications supplémentaires pour null, par exemple
Customer customer = findCustomer("...");
if (customer != null && customer.getOrders() > 0)
{
...
}
font partie de la sémantique de ce que je fais et je ne voudrais pas simplement les "sauter" afin de rendre le code plus lisible. Je ne pense pas que ce soit une bonne pratique de simplifier la sémantique du problème en question, simplement pour simplifier le code.
Bien sûr, puisque la vérification de la nullité est très fréquente, il est utile que le langage prenne en charge une syntaxe spéciale.
J'envisagerais également d'utiliser le modèle d'objet nul (comme suggéré par Laf) tant que je peux distinguer l'objet nul d'une classe de tous les autres objets.